@ryuu-reinzz/baileys 3.5.1 → 5.0.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 +30 -25
- package/WAProto/fix-imports.js +22 -18
- package/WAProto/index.js +22 -18
- package/lib/Defaults/index.js +10 -9
- package/lib/Signal/libsignal.js +46 -19
- package/lib/Signal/lid-mapping.js +6 -0
- package/lib/Socket/chats.js +241 -39
- package/lib/Socket/groups.js +20 -0
- package/lib/Socket/messages-recv.js +736 -314
- package/lib/Socket/messages-send.js +279 -129
- package/lib/Socket/newsletter.js +2 -2
- package/lib/Socket/socket.js +56 -25
- package/lib/Types/{Newsletter.js → Mex.js} +9 -3
- package/lib/Types/State.js +43 -0
- package/lib/Types/index.js +1 -1
- package/lib/Utils/auth-utils.js +12 -0
- package/lib/Utils/chat-utils.js +80 -20
- package/lib/Utils/companion-reg-client-utils.js +35 -0
- package/lib/Utils/decode-wa-message.js +34 -0
- package/lib/Utils/event-buffer.js +49 -1
- package/lib/Utils/generics.js +12 -3
- package/lib/Utils/history.js +12 -9
- package/lib/Utils/identity-change-handler.js +1 -0
- package/lib/Utils/index.js +3 -1
- package/lib/Utils/link-preview.js +2 -2
- package/lib/Utils/message-retry-manager.js +40 -0
- package/lib/Utils/messages-media.js +21 -7
- package/lib/Utils/messages.js +28 -5
- package/lib/Utils/offline-node-processor.js +40 -0
- package/lib/Utils/process-message.js +103 -1
- package/lib/Utils/signal.js +42 -0
- package/lib/Utils/stanza-ack.js +38 -0
- package/lib/Utils/sync-action-utils.js +1 -0
- package/lib/Utils/tc-token-utils.js +149 -4
- package/lib/Utils/validate-connection.js +3 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +26 -3
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +25 -0
- package/lib/WAUSync/Protocols/index.js +1 -0
- package/lib/WAUSync/USyncQuery.js +6 -2
- package/lib/WAUSync/USyncUser.js +8 -0
- package/package.json +39 -12
package/README.md
CHANGED
|
@@ -56,18 +56,23 @@ To run the example script, download or clone the repo and then type the followin
|
|
|
56
56
|
|
|
57
57
|
Use the stable version:
|
|
58
58
|
```
|
|
59
|
-
yarn add @
|
|
59
|
+
yarn add @whiskeysockets/baileys
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Use the edge version (no guarantee of stability, but latest fixes + features)
|
|
63
|
+
```
|
|
64
|
+
yarn add github:WhiskeySockets/Baileys
|
|
60
65
|
```
|
|
61
66
|
|
|
62
67
|
Then import your code using:
|
|
63
68
|
```ts
|
|
64
|
-
import makeWASocket from '@
|
|
69
|
+
import makeWASocket from '@whiskeysockets/baileys'
|
|
65
70
|
```
|
|
66
71
|
|
|
67
72
|
# Links
|
|
68
73
|
|
|
69
74
|
- [Discord](https://discord.gg/WeJM5FP9GG)
|
|
70
|
-
- [Docs](https://
|
|
75
|
+
- [Docs](https://baileys.wiki/docs/intro/)
|
|
71
76
|
|
|
72
77
|
# Index
|
|
73
78
|
|
|
@@ -182,15 +187,15 @@ WhatsApp provides a multi-device API that allows Baileys to be authenticated as
|
|
|
182
187
|
> **[Here](#example-to-start) is a simple example of event handling**
|
|
183
188
|
|
|
184
189
|
> [!TIP]
|
|
185
|
-
> **You can see all supported socket configs [
|
|
190
|
+
> **You can see all supported socket configs in the [SocketConfig type alias](https://baileys.wiki/docs/api/type-aliases/SocketConfig/) (Recommended)**
|
|
186
191
|
|
|
187
192
|
### Starting socket with **QR-CODE**
|
|
188
193
|
|
|
189
194
|
> [!TIP]
|
|
190
|
-
> You can customize browser name if you connect with **QR-CODE**, with `Browser` constant, we have some browsers config, **see [
|
|
195
|
+
> You can customize browser name if you connect with **QR-CODE**, with `Browser` constant, we have some browsers config, **see the [BrowsersMap type alias](https://baileys.wiki/docs/api/type-aliases/BrowsersMap/)**
|
|
191
196
|
|
|
192
197
|
```ts
|
|
193
|
-
import makeWASocket from '@
|
|
198
|
+
import makeWASocket from '@whiskeysockets/baileys'
|
|
194
199
|
|
|
195
200
|
const sock = makeWASocket({
|
|
196
201
|
// can provide additional config here
|
|
@@ -210,7 +215,7 @@ If the connection is successful, you will see a QR code printed on your terminal
|
|
|
210
215
|
The phone number can't have `+` or `()` or `-`, only numbers, you must provide country code
|
|
211
216
|
|
|
212
217
|
```ts
|
|
213
|
-
import makeWASocket from '@
|
|
218
|
+
import makeWASocket from '@whiskeysockets/baileys'
|
|
214
219
|
|
|
215
220
|
const sock = makeWASocket({
|
|
216
221
|
// can provide additional config here
|
|
@@ -283,7 +288,7 @@ You obviously don't want to keep scanning the QR code every time you want to con
|
|
|
283
288
|
|
|
284
289
|
So, you can load the credentials to log back in:
|
|
285
290
|
```ts
|
|
286
|
-
import makeWASocket, { useMultiFileAuthState } from '@
|
|
291
|
+
import makeWASocket, { useMultiFileAuthState } from '@whiskeysockets/baileys'
|
|
287
292
|
|
|
288
293
|
const { state, saveCreds } = await useMultiFileAuthState('auth_info_baileys')
|
|
289
294
|
|
|
@@ -307,7 +312,7 @@ sock.ev.on('creds.update', saveCreds)
|
|
|
307
312
|
They're all nicely typed up, so you shouldn't have any issues with an Intellisense editor like VS Code.
|
|
308
313
|
|
|
309
314
|
> [!IMPORTANT]
|
|
310
|
-
> **The events are [
|
|
315
|
+
> **The events are in the [BaileysEventMap type alias](https://baileys.wiki/docs/api/type-aliases/BaileysEventMap/)**, it's important you see all events
|
|
311
316
|
|
|
312
317
|
You can listen to these events like this:
|
|
313
318
|
```ts
|
|
@@ -326,7 +331,7 @@ sock.ev.on('messages.upsert', ({ messages }) => {
|
|
|
326
331
|
> For reliable serialization of the authentication state, especially when storing as JSON, always use the BufferJSON utility.
|
|
327
332
|
|
|
328
333
|
```ts
|
|
329
|
-
import makeWASocket, { DisconnectReason, useMultiFileAuthState } from '@
|
|
334
|
+
import makeWASocket, { DisconnectReason, useMultiFileAuthState } from '@whiskeysockets/baileys'
|
|
330
335
|
import { Boom } from '@hapi/boom'
|
|
331
336
|
|
|
332
337
|
async function connectToWhatsApp () {
|
|
@@ -408,7 +413,7 @@ sock.ev.on('messages.update', event => {
|
|
|
408
413
|
It can be used as follows:
|
|
409
414
|
|
|
410
415
|
```ts
|
|
411
|
-
import makeWASocket, { makeInMemoryStore } from '@
|
|
416
|
+
import makeWASocket, { makeInMemoryStore } from '@whiskeysockets/baileys'
|
|
412
417
|
// the store maintains the data of the WA connection in memory
|
|
413
418
|
// can be written out to a file & read from it
|
|
414
419
|
const store = makeInMemoryStore({ })
|
|
@@ -457,8 +462,8 @@ The store also provides some simple functions such as `loadMessages` that utiliz
|
|
|
457
462
|
## Sending Messages
|
|
458
463
|
|
|
459
464
|
- Send all types of messages with a single function
|
|
460
|
-
- **[
|
|
461
|
-
- **[
|
|
465
|
+
- **In the [AnyMessageContent type alias](https://baileys.wiki/docs/api/type-aliases/AnyMessageContent/) you can see all message contents supported, like text message**
|
|
466
|
+
- **In the [MiscMessageGenerationOptions type alias](https://baileys.wiki/docs/api/type-aliases/MiscMessageGenerationOptions/) you can see all options supported, like quote message**
|
|
462
467
|
|
|
463
468
|
```ts
|
|
464
469
|
const jid: string
|
|
@@ -493,7 +498,7 @@ await sock.sendMessage(
|
|
|
493
498
|
```
|
|
494
499
|
|
|
495
500
|
#### Forward Messages
|
|
496
|
-
- You need to have message object, can be retrieved from [store](#implementing-a-data-store) or use a [message](https://baileys.
|
|
501
|
+
- You need to have message object, can be retrieved from [store](#implementing-a-data-store) or use a [message](https://baileys.wiki/docs/api/type-aliases/WAMessage/) object
|
|
497
502
|
```ts
|
|
498
503
|
const msg = getMessageFromStore() // implement this on your end
|
|
499
504
|
await sock.sendMessage(jid, { forward: msg }) // WA forward the message!
|
|
@@ -532,7 +537,7 @@ await sock.sendMessage(
|
|
|
532
537
|
```
|
|
533
538
|
|
|
534
539
|
#### Reaction Message
|
|
535
|
-
- You need to pass the key of message, you can retrieve from [store](#implementing-a-data-store) or use a [key](https://baileys.
|
|
540
|
+
- You need to pass the key of message, you can retrieve from [store](#implementing-a-data-store) or use a [key](https://baileys.wiki/docs/api/type-aliases/WAMessageKey/) object
|
|
536
541
|
```ts
|
|
537
542
|
await sock.sendMessage(
|
|
538
543
|
jid,
|
|
@@ -546,7 +551,7 @@ await sock.sendMessage(
|
|
|
546
551
|
```
|
|
547
552
|
|
|
548
553
|
#### Pin Message
|
|
549
|
-
- You need to pass the key of message, you can retrieve from [store](#implementing-a-data-store) or use a [key](https://baileys.
|
|
554
|
+
- You need to pass the key of message, you can retrieve from [store](#implementing-a-data-store) or use a [key](https://baileys.wiki/docs/api/type-aliases/WAMessageKey/) object
|
|
550
555
|
|
|
551
556
|
- Time can be:
|
|
552
557
|
|
|
@@ -594,7 +599,7 @@ await sock.sendMessage(
|
|
|
594
599
|
await sock.sendMessage(
|
|
595
600
|
jid,
|
|
596
601
|
{
|
|
597
|
-
text: 'Hi, this was sent using https://github.com/
|
|
602
|
+
text: 'Hi, this was sent using https://github.com/whiskeysockets/baileys'
|
|
598
603
|
}
|
|
599
604
|
)
|
|
600
605
|
```
|
|
@@ -604,7 +609,7 @@ await sock.sendMessage(
|
|
|
604
609
|
Sending media (video, stickers, images) is easier & more efficient than ever.
|
|
605
610
|
|
|
606
611
|
> [!NOTE]
|
|
607
|
-
> In media messages, you can pass `{ stream: Stream }` or `{ url: Url }` or `Buffer` directly, you can see more [
|
|
612
|
+
> In media messages, you can pass `{ stream: Stream }` or `{ url: Url }` or `Buffer` directly, you can see more in the [WAMediaUpload type alias](https://baileys.wiki/docs/api/type-aliases/WAMediaUpload/)
|
|
608
613
|
|
|
609
614
|
- When specifying a media url, Baileys never loads the entire buffer into memory; it even encrypts the media as a readable stream.
|
|
610
615
|
|
|
@@ -724,7 +729,7 @@ await sock.sendMessage(jid, {
|
|
|
724
729
|
If you want to save the media you received
|
|
725
730
|
```ts
|
|
726
731
|
import { createWriteStream } from 'fs'
|
|
727
|
-
import { downloadMediaMessage, getContentType } from '@
|
|
732
|
+
import { downloadMediaMessage, getContentType } from '@whiskeysockets/baileys'
|
|
728
733
|
|
|
729
734
|
sock.ev.on('messages.upsert', async ({ [m] }) => {
|
|
730
735
|
if (!m.message) return // if there is no text or media message
|
|
@@ -769,7 +774,7 @@ await sock.rejectCall(callId, callFrom)
|
|
|
769
774
|
## Send States in Chat
|
|
770
775
|
|
|
771
776
|
### Reading Messages
|
|
772
|
-
- A set of message [keys](https://baileys.
|
|
777
|
+
- A set of message [keys](https://baileys.wiki/docs/api/type-aliases/WAMessageKey/) must be explicitly marked read now.
|
|
773
778
|
- You cannot mark an entire 'chat' read as it were with Baileys Web.
|
|
774
779
|
This means you have to keep track of unread messages.
|
|
775
780
|
|
|
@@ -784,7 +789,7 @@ On a `WAMessage`, the `messageID` can be accessed using ```messageID = message.k
|
|
|
784
789
|
|
|
785
790
|
### Update Presence
|
|
786
791
|
|
|
787
|
-
- ``` presence ``` can be one of [
|
|
792
|
+
- ``` presence ``` can be one of the values in the [WAPresence type alias](https://baileys.wiki/docs/api/type-aliases/WAPresence/)
|
|
788
793
|
- The presence expires after about 10 seconds.
|
|
789
794
|
- This lets the person/group with `jid` know whether you're online, offline, typing etc.
|
|
790
795
|
|
|
@@ -986,7 +991,7 @@ await sock.updateProfileName('My name')
|
|
|
986
991
|
- To change your display picture or a group's
|
|
987
992
|
|
|
988
993
|
> [!NOTE]
|
|
989
|
-
> Like media messages, you can pass `{ stream: Stream }` or `{ url: Url }` or `Buffer` directly, you can see more [
|
|
994
|
+
> Like media messages, you can pass `{ stream: Stream }` or `{ url: Url }` or `Buffer` directly, you can see more in the [WAMediaUpload type alias](https://baileys.wiki/docs/api/type-aliases/WAMediaUpload/)
|
|
990
995
|
|
|
991
996
|
```ts
|
|
992
997
|
await sock.updateProfilePicture(jid, { url: './new-profile-picture.jpeg' })
|
|
@@ -1198,8 +1203,8 @@ await sock.sendMessage(
|
|
|
1198
1203
|
}
|
|
1199
1204
|
)
|
|
1200
1205
|
```
|
|
1201
|
-
- Message body can be a `extendedTextMessage` or `imageMessage` or `videoMessage` or `voiceMessage`, see [
|
|
1202
|
-
- You can add `backgroundColor` and other options in the message options, see [
|
|
1206
|
+
- Message body can be a `extendedTextMessage` or `imageMessage` or `videoMessage` or `voiceMessage`, see the [AnyRegularMessageContent type alias](https://baileys.wiki/docs/api/type-aliases/AnyRegularMessageContent/)
|
|
1207
|
+
- You can add `backgroundColor` and other options in the message options, see the [MiscMessageGenerationOptions type alias](https://baileys.wiki/docs/api/type-aliases/MiscMessageGenerationOptions/)
|
|
1203
1208
|
- `broadcast: true` enables broadcast mode
|
|
1204
1209
|
- `statusJidList`: a list of people that you can get which you need to provide, which are the people who will get this status message.
|
|
1205
1210
|
|
|
@@ -1283,7 +1288,7 @@ sock.ws.on('CB:edge_routing,id:abcd,routing_info', (node: BinaryNode) => { })
|
|
|
1283
1288
|
```
|
|
1284
1289
|
|
|
1285
1290
|
# License
|
|
1286
|
-
Copyright (c) 2025
|
|
1291
|
+
Copyright (c) 2025 Rajeh Taher/WhiskeySockets
|
|
1287
1292
|
|
|
1288
1293
|
Licensed under the MIT License:
|
|
1289
1294
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
package/WAProto/fix-imports.js
CHANGED
|
@@ -18,14 +18,18 @@ try {
|
|
|
18
18
|
'\tif (typeof value === "number") {\n' +
|
|
19
19
|
'\t\treturn String(value);\n' +
|
|
20
20
|
'\t}\n' +
|
|
21
|
-
'\
|
|
22
|
-
'\t
|
|
21
|
+
'\t// Fast path: convert Long {low, high} directly via native BigInt\n' +
|
|
22
|
+
'\t// BigInt.toString() is a native C++ operation, much faster than Long\'s pure JS division loops\n' +
|
|
23
|
+
'\tif (value && typeof value.low === "number" && typeof value.high === "number") {\n' +
|
|
24
|
+
'\t\tconst lo = BigInt(value.low >>> 0);\n' +
|
|
25
|
+
'\t\tconst hi = BigInt(value.high >>> 0);\n' +
|
|
26
|
+
'\t\tconst combined = (hi << 32n) | lo;\n' +
|
|
27
|
+
'\t\tif (!unsigned && value.high < 0) {\n' +
|
|
28
|
+
'\t\t\treturn (combined - (1n << 64n)).toString();\n' +
|
|
29
|
+
'\t\t}\n' +
|
|
30
|
+
'\t\treturn combined.toString();\n' +
|
|
23
31
|
'\t}\n' +
|
|
24
|
-
'\
|
|
25
|
-
'\tconst prepared = unsigned && normalized && typeof normalized.toUnsigned === "function"\n' +
|
|
26
|
-
'\t\t? normalized.toUnsigned()\n' +
|
|
27
|
-
'\t\t: normalized;\n' +
|
|
28
|
-
'\treturn prepared.toString();\n' +
|
|
32
|
+
'\treturn String(value);\n' +
|
|
29
33
|
'}\n\n'
|
|
30
34
|
const longToNumberHelper =
|
|
31
35
|
'function longToNumber(value, unsigned) {\n' +
|
|
@@ -33,19 +37,19 @@ try {
|
|
|
33
37
|
'\t\treturn value;\n' +
|
|
34
38
|
'\t}\n' +
|
|
35
39
|
'\tif (typeof value === "string") {\n' +
|
|
36
|
-
'\t\tconst numeric = Number(value);\n' +
|
|
37
|
-
'\t\treturn numeric;\n' +
|
|
38
|
-
'\t}\n' +
|
|
39
|
-
'\tif (!$util.Long) {\n' +
|
|
40
40
|
'\t\treturn Number(value);\n' +
|
|
41
41
|
'\t}\n' +
|
|
42
|
-
'\
|
|
43
|
-
'\
|
|
44
|
-
'\t\
|
|
45
|
-
'\t\
|
|
46
|
-
'\t\
|
|
47
|
-
'\t\
|
|
48
|
-
'\treturn
|
|
42
|
+
'\t// Fast path: convert Long {low, high} directly via native BigInt\n' +
|
|
43
|
+
'\tif (value && typeof value.low === "number" && typeof value.high === "number") {\n' +
|
|
44
|
+
'\t\tconst lo = BigInt(value.low >>> 0);\n' +
|
|
45
|
+
'\t\tconst hi = BigInt(value.high >>> 0);\n' +
|
|
46
|
+
'\t\tconst combined = (hi << 32n) | lo;\n' +
|
|
47
|
+
'\t\tif (!unsigned && value.high < 0) {\n' +
|
|
48
|
+
'\t\t\treturn Number(combined - (1n << 64n));\n' +
|
|
49
|
+
'\t\t}\n' +
|
|
50
|
+
'\t\treturn Number(combined);\n' +
|
|
51
|
+
'\t}\n' +
|
|
52
|
+
'\treturn Number(value);\n' +
|
|
49
53
|
'}\n\n'
|
|
50
54
|
|
|
51
55
|
if (!content.includes('function longToString(')) {
|
package/WAProto/index.js
CHANGED
|
@@ -12,14 +12,18 @@ function longToString(value, unsigned) {
|
|
|
12
12
|
if (typeof value === "number") {
|
|
13
13
|
return String(value);
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
// Fast path: convert Long {low, high} directly via native BigInt
|
|
16
|
+
// BigInt.toString() is a native C++ operation, much faster than Long's pure JS division loops
|
|
17
|
+
if (value && typeof value.low === "number" && typeof value.high === "number") {
|
|
18
|
+
const lo = BigInt(value.low >>> 0);
|
|
19
|
+
const hi = BigInt(value.high >>> 0);
|
|
20
|
+
const combined = (hi << 32n) | lo;
|
|
21
|
+
if (!unsigned && value.high < 0) {
|
|
22
|
+
return (combined - (1n << 64n)).toString();
|
|
23
|
+
}
|
|
24
|
+
return combined.toString();
|
|
17
25
|
}
|
|
18
|
-
|
|
19
|
-
const prepared = unsigned && normalized && typeof normalized.toUnsigned === "function"
|
|
20
|
-
? normalized.toUnsigned()
|
|
21
|
-
: normalized;
|
|
22
|
-
return prepared.toString();
|
|
26
|
+
return String(value);
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
function longToNumber(value, unsigned) {
|
|
@@ -27,19 +31,19 @@ function longToNumber(value, unsigned) {
|
|
|
27
31
|
return value;
|
|
28
32
|
}
|
|
29
33
|
if (typeof value === "string") {
|
|
30
|
-
const numeric = Number(value);
|
|
31
|
-
return numeric;
|
|
32
|
-
}
|
|
33
|
-
if (!$util.Long) {
|
|
34
34
|
return Number(value);
|
|
35
35
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
36
|
+
// Fast path: convert Long {low, high} directly via native BigInt
|
|
37
|
+
if (value && typeof value.low === "number" && typeof value.high === "number") {
|
|
38
|
+
const lo = BigInt(value.low >>> 0);
|
|
39
|
+
const hi = BigInt(value.high >>> 0);
|
|
40
|
+
const combined = (hi << 32n) | lo;
|
|
41
|
+
if (!unsigned && value.high < 0) {
|
|
42
|
+
return Number(combined - (1n << 64n));
|
|
43
|
+
}
|
|
44
|
+
return Number(combined);
|
|
45
|
+
}
|
|
46
|
+
return Number(value);
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
export const proto = $root.proto = (() => {
|
package/lib/Defaults/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { proto } from '../../WAProto/index.js';
|
|
|
2
2
|
import { makeLibSignalRepository } from '../Signal/libsignal.js';
|
|
3
3
|
import { Browsers } from '../Utils/browser-utils.js';
|
|
4
4
|
import logger from '../Utils/logger.js';
|
|
5
|
-
const version = [2, 3000,
|
|
5
|
+
const version = [2, 3000, 1035194821];
|
|
6
6
|
export const UNAUTHORIZED_CODES = [401, 403, 419];
|
|
7
7
|
export const DEFAULT_ORIGIN = 'https://web.whatsapp.com';
|
|
8
8
|
export const CALL_VIDEO_PREFIX = 'https://call.whatsapp.com/video/';
|
|
@@ -39,9 +39,15 @@ export const PROCESSABLE_HISTORY_TYPES = [
|
|
|
39
39
|
proto.HistorySync.HistorySyncType.NON_BLOCKING_DATA,
|
|
40
40
|
proto.HistorySync.HistorySyncType.INITIAL_STATUS_V3
|
|
41
41
|
];
|
|
42
|
+
export const DEFAULT_CACHE_TTLS = {
|
|
43
|
+
SIGNAL_STORE: 5 * 60, // 5 minutes
|
|
44
|
+
MSG_RETRY: 60 * 60, // 1 hour
|
|
45
|
+
CALL_OFFER: 5 * 60, // 5 minutes
|
|
46
|
+
USER_DEVICES: 5 * 60 // 5 minutes
|
|
47
|
+
};
|
|
42
48
|
export const DEFAULT_CONNECTION_CONFIG = {
|
|
43
49
|
version: version,
|
|
44
|
-
browser: Browsers.macOS('
|
|
50
|
+
browser: Browsers.macOS('Safari'),
|
|
45
51
|
waWebSocketUrl: 'wss://web.whatsapp.com/ws/chat',
|
|
46
52
|
connectTimeoutMs: 20000,
|
|
47
53
|
keepAliveIntervalMs: 30000,
|
|
@@ -109,16 +115,11 @@ export const MEDIA_HKDF_KEY_MAPPING = {
|
|
|
109
115
|
'biz-cover-photo': 'Image'
|
|
110
116
|
};
|
|
111
117
|
export const MEDIA_KEYS = Object.keys(MEDIA_PATH_MAP);
|
|
118
|
+
/** 120s timeout for history sync stall detection, same as WA Web's handleChunkProgress / restartPausedTimer (g = 120) */
|
|
119
|
+
export const HISTORY_SYNC_PAUSED_TIMEOUT_MS = 120000;
|
|
112
120
|
export const MIN_PREKEY_COUNT = 5;
|
|
113
121
|
export const INITIAL_PREKEY_COUNT = 812;
|
|
114
122
|
export const UPLOAD_TIMEOUT = 30000; // 30 seconds
|
|
115
|
-
export const MIN_UPLOAD_INTERVAL = 5000; // 5 seconds minimum between uploads
|
|
116
|
-
export const DEFAULT_CACHE_TTLS = {
|
|
117
|
-
SIGNAL_STORE: 5 * 60, // 5 minutes
|
|
118
|
-
MSG_RETRY: 60 * 60, // 1 hour
|
|
119
|
-
CALL_OFFER: 5 * 60, // 5 minutes
|
|
120
|
-
USER_DEVICES: 5 * 60 // 5 minutes
|
|
121
|
-
};
|
|
122
123
|
export const TimeMs = {
|
|
123
124
|
Minute: 60 * 1000,
|
|
124
125
|
Hour: 60 * 60 * 1000,
|
package/lib/Signal/libsignal.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-ignore
|
|
2
2
|
import * as libsignal from 'libsignal';
|
|
3
3
|
// @ts-ignore
|
|
4
|
-
import
|
|
4
|
+
import { PreKeyWhisperMessage } from 'libsignal/src/protobufs.js';
|
|
5
5
|
import { LRUCache } from 'lru-cache';
|
|
6
6
|
import { generateSignalPubKey } from '../Utils/index.js';
|
|
7
7
|
import { isHostedLidUser, isHostedPnUser, isLidUser, isPnUser, jidDecode, transferDevice, WAJIDDomains } from '../WABinary/index.js';
|
|
@@ -10,7 +10,6 @@ import { SenderKeyRecord } from './Group/sender-key-record.js';
|
|
|
10
10
|
import { GroupCipher, GroupSessionBuilder, SenderKeyDistributionMessage } from './Group/index.js';
|
|
11
11
|
import { LIDMappingStore } from './lid-mapping.js';
|
|
12
12
|
/** Extract identity key from PreKeyWhisperMessage for identity change detection */
|
|
13
|
-
const { PreKeyWhisperMessage } = signals;
|
|
14
13
|
function extractIdentityFromPkmsg(ciphertext) {
|
|
15
14
|
try {
|
|
16
15
|
if (!ciphertext || ciphertext.length < 2) {
|
|
@@ -41,6 +40,16 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
41
40
|
ttlAutopurge: true,
|
|
42
41
|
updateAgeOnGet: true
|
|
43
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
|
+
};
|
|
44
53
|
const repository = {
|
|
45
54
|
decryptGroupMessage({ group, authorJid, msg }) {
|
|
46
55
|
const senderName = jidToSignalSenderKeyName(group, authorJid);
|
|
@@ -113,27 +122,43 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
113
122
|
}, jid);
|
|
114
123
|
},
|
|
115
124
|
async encryptGroupMessage({ group, meId, data }) {
|
|
116
|
-
const senderName = jidToSignalSenderKeyName(group, meId);
|
|
117
|
-
const builder = new GroupSessionBuilder(storage);
|
|
118
|
-
const senderNameStr = senderName.toString();
|
|
119
125
|
return parsedKeys.transaction(async () => {
|
|
120
|
-
const {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
const senderKeyDistributionMessage = await builder.create(senderName);
|
|
125
|
-
const session = new GroupCipher(storage, senderName);
|
|
126
|
-
const ciphertext = await session.encrypt(data);
|
|
127
|
-
return {
|
|
128
|
-
ciphertext,
|
|
129
|
-
senderKeyDistributionMessage: senderKeyDistributionMessage.serialize()
|
|
130
|
-
};
|
|
126
|
+
const { senderName, skdm } = await ensureSenderKeyAndCreateSkdm(group, meId);
|
|
127
|
+
const ciphertext = await new GroupCipher(storage, senderName).encrypt(data);
|
|
128
|
+
return { ciphertext, senderKeyDistributionMessage: skdm.serialize() };
|
|
131
129
|
}, group);
|
|
132
130
|
},
|
|
131
|
+
async getSenderKeyDistributionMessage({ group, meId }) {
|
|
132
|
+
return parsedKeys.transaction(async () => {
|
|
133
|
+
const { skdm } = await ensureSenderKeyAndCreateSkdm(group, meId);
|
|
134
|
+
return skdm.serialize();
|
|
135
|
+
}, group);
|
|
136
|
+
},
|
|
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
|
+
},
|
|
133
156
|
async injectE2ESession({ jid, session }) {
|
|
134
157
|
logger.trace({ jid }, 'injecting E2EE session');
|
|
135
158
|
const cipher = new libsignal.SessionBuilder(storage, jidToSignalProtocolAddress(jid));
|
|
136
159
|
return parsedKeys.transaction(async () => {
|
|
160
|
+
// libsignal runtime accepts an absent prekey (initOutgoing checks `device.preKey && ...`)
|
|
161
|
+
// but the bundled .d.ts marks it required.
|
|
137
162
|
await cipher.initOutgoing(session);
|
|
138
163
|
}, jid);
|
|
139
164
|
},
|
|
@@ -172,6 +197,10 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
172
197
|
await auth.keys.set({ session: sessionUpdates });
|
|
173
198
|
}, `delete-${jids.length}-sessions`);
|
|
174
199
|
},
|
|
200
|
+
close() {
|
|
201
|
+
migratedSessionCache.clear();
|
|
202
|
+
lidMapping.close();
|
|
203
|
+
},
|
|
175
204
|
async migrateSession(fromJid, toJid) {
|
|
176
205
|
// TODO: use usync to handle this entire mess
|
|
177
206
|
if (!fromJid || (!isLidUser(toJid) && !isHostedLidUser(toJid)))
|
|
@@ -342,9 +371,7 @@ function signalStorage({ creds, keys }, lidMapping) {
|
|
|
342
371
|
saveIdentity: async (id, identityKey) => {
|
|
343
372
|
const wireJid = await resolveLIDSignalAddress(id);
|
|
344
373
|
const { [wireJid]: existingKey } = await keys.get('identity-key', [wireJid]);
|
|
345
|
-
const keysMatch = existingKey &&
|
|
346
|
-
existingKey.length === identityKey.length &&
|
|
347
|
-
existingKey.every((byte, i) => byte === identityKey[i]);
|
|
374
|
+
const keysMatch = existingKey?.length === identityKey.length && existingKey.every((byte, i) => byte === identityKey[i]);
|
|
348
375
|
if (existingKey && !keysMatch) {
|
|
349
376
|
// Identity changed - clear session and update key
|
|
350
377
|
await keys.set({
|
|
@@ -267,5 +267,11 @@ export class LIDMappingStore {
|
|
|
267
267
|
}
|
|
268
268
|
return Object.values(successfulPairs).length ? Object.values(successfulPairs) : null;
|
|
269
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* Close the cache and release resources
|
|
272
|
+
*/
|
|
273
|
+
close() {
|
|
274
|
+
this.mappingCache.clear();
|
|
275
|
+
}
|
|
270
276
|
}
|
|
271
277
|
//# sourceMappingURL=lid-mapping.js.map
|