@nexustechpro/baileys 1.1.7 → 1.1.9
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/WAProto/GenerateStatics.sh +3 -0
- package/lib/Defaults/baileys-version.json +3 -0
- package/lib/Defaults/index.js +150 -128
- package/lib/Defaults/phonenumber-mcc.json +223 -0
- package/lib/Signal/libsignal.js +19 -1
- package/lib/Socket/index.js +8 -4
- package/lib/Socket/messages-recv.js +18 -7
- package/lib/Socket/messages-send.js +60 -9
- package/lib/Socket/nexus-handler.js +1 -1
- package/lib/Socket/registration.js +197 -0
- package/lib/Socket/socket.js +8 -27
- package/lib/Utils/decode-wa-message.js +6 -0
- package/lib/Utils/generics.js +1 -1
- package/lib/Utils/link-preview.js +11 -7
- package/lib/index.js +3 -4
- package/package.json +14 -7
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
yarn pbjs -t static-module --no-beautify -w es6 --no-bundle --no-delimited --no-verify --no-comments -o ./index.js ./WAProto.proto;
|
|
2
|
+
yarn pbjs -t static-module --no-beautify -w es6 --no-bundle --no-delimited --no-verify ./WAProto.proto | yarn pbts --no-comments -o ./index.d.ts -;
|
|
3
|
+
node ./fix-imports.js
|
package/lib/Defaults/index.js
CHANGED
|
@@ -1,151 +1,173 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
import { createRequire } from 'module';
|
|
3
|
+
import { proto } from '../../WAProto/index.js';
|
|
4
|
+
import { makeLibSignalRepository } from '../Signal/libsignal.js';
|
|
5
|
+
import { Browsers } from '../Utils/browser-utils.js';
|
|
6
|
+
import logger from '../Utils/logger.js';
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const PHONENUMBER_MCC = require('./phonenumber-mcc.json');
|
|
9
|
+
export { PHONENUMBER_MCC };
|
|
10
|
+
const version = [2, 3000, 1027934701];
|
|
5
11
|
|
|
6
|
-
const
|
|
12
|
+
export const UNAUTHORIZED_CODES = [401, 403, 419];
|
|
7
13
|
|
|
8
|
-
export const
|
|
14
|
+
export const DEFAULT_ORIGIN = 'https://web.whatsapp.com';
|
|
15
|
+
export const CALL_VIDEO_PREFIX = 'https://call.whatsapp.com/video/';
|
|
16
|
+
export const CALL_AUDIO_PREFIX = 'https://call.whatsapp.com/voice/';
|
|
17
|
+
export const DEF_CALLBACK_PREFIX = 'CB:';
|
|
18
|
+
export const DEF_TAG_PREFIX = 'TAG:';
|
|
19
|
+
export const PHONE_CONNECTION_CB = 'CB:Pong';
|
|
9
20
|
|
|
10
|
-
export const
|
|
11
|
-
export const
|
|
12
|
-
export const
|
|
13
|
-
export const
|
|
14
|
-
export const DEF_TAG_PREFIX = 'TAG:'
|
|
15
|
-
export const PHONE_CONNECTION_CB = 'CB:Pong'
|
|
21
|
+
export const WA_ADV_ACCOUNT_SIG_PREFIX = Buffer.from([6, 0]);
|
|
22
|
+
export const WA_ADV_DEVICE_SIG_PREFIX = Buffer.from([6, 1]);
|
|
23
|
+
export const WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX = Buffer.from([6, 5]);
|
|
24
|
+
export const WA_ADV_HOSTED_DEVICE_SIG_PREFIX = Buffer.from([6, 6]);
|
|
16
25
|
|
|
17
|
-
export const
|
|
18
|
-
export const WA_ADV_DEVICE_SIG_PREFIX = Buffer.from([6, 1])
|
|
19
|
-
export const WA_ADV_HOSTED_ACCOUNT_SIG_PREFIX = Buffer.from([6, 5])
|
|
20
|
-
export const WA_ADV_HOSTED_DEVICE_SIG_PREFIX = Buffer.from([6, 6])
|
|
26
|
+
export const WA_DEFAULT_EPHEMERAL = 7 * 24 * 60 * 60;
|
|
21
27
|
|
|
22
|
-
export const
|
|
28
|
+
export const STATUS_EXPIRY_SECONDS = 24 * 60 * 60;
|
|
23
29
|
|
|
24
|
-
export const
|
|
30
|
+
export const PLACEHOLDER_MAX_AGE_SECONDS = 14 * 24 * 60 * 60;
|
|
25
31
|
|
|
26
|
-
export const
|
|
32
|
+
export const BATCH_SIZE = 500;
|
|
27
33
|
|
|
28
|
-
export const
|
|
34
|
+
export const NOISE_MODE = 'Noise_XX_25519_AESGCM_SHA256\0\0\0\0';
|
|
35
|
+
export const DICT_VERSION = 3;
|
|
36
|
+
export const KEY_BUNDLE_TYPE = Buffer.from([5]);
|
|
37
|
+
export const NOISE_WA_HEADER = Buffer.from([87, 65, 6, DICT_VERSION]);
|
|
29
38
|
|
|
30
|
-
export const
|
|
31
|
-
export const DICT_VERSION = 3
|
|
32
|
-
export const KEY_BUNDLE_TYPE = Buffer.from([5])
|
|
33
|
-
export const NOISE_WA_HEADER = Buffer.from([87, 65, 6, DICT_VERSION])
|
|
34
|
-
|
|
35
|
-
export const URL_REGEX = /https:\/\/(?![^:@\/\s]+:[^:@\/\s]+@)[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(:\d+)?(\/[^\s]*)?/g
|
|
39
|
+
export const URL_REGEX = /https:\/\/(?![^:@\/\s]+:[^:@\/\s]+@)[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(:\d+)?(\/[^\s]*)?/g;
|
|
36
40
|
|
|
37
41
|
export const WA_CERT_DETAILS = {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
+
SERIAL: 0,
|
|
43
|
+
ISSUER: 'WhatsAppLongTerm1',
|
|
44
|
+
PUBLIC_KEY: Buffer.from('142375574d0a587166aae71ebe516437c4a28b73e3695c6ce1f7f9545da8ee6b', 'hex')
|
|
45
|
+
};
|
|
42
46
|
|
|
43
47
|
export const PROCESSABLE_HISTORY_TYPES = [
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
]
|
|
48
|
+
proto.HistorySync.HistorySyncType.INITIAL_BOOTSTRAP,
|
|
49
|
+
proto.HistorySync.HistorySyncType.PUSH_NAME,
|
|
50
|
+
proto.HistorySync.HistorySyncType.RECENT,
|
|
51
|
+
proto.HistorySync.HistorySyncType.FULL,
|
|
52
|
+
proto.HistorySync.HistorySyncType.ON_DEMAND,
|
|
53
|
+
proto.HistorySync.HistorySyncType.NON_BLOCKING_DATA,
|
|
54
|
+
proto.HistorySync.HistorySyncType.INITIAL_STATUS_V3
|
|
55
|
+
];
|
|
56
|
+
export const MOBILE_ENDPOINT = 'g.whatsapp.net';
|
|
57
|
+
export const MOBILE_PORT = 443;
|
|
58
|
+
|
|
59
|
+
const WA_VERSION = '2.25.23.24';
|
|
60
|
+
const WA_VERSION_HASH = createHash('md5').update(WA_VERSION).digest('hex');
|
|
61
|
+
|
|
62
|
+
export const MOBILE_TOKEN = Buffer.from('0a1mLfGUIBVrMKF1RdvLI5lkRBvof6vn0fD2QRSM' + WA_VERSION_HASH);
|
|
63
|
+
export const MOBILE_REGISTRATION_ENDPOINT = 'https://v.whatsapp.net/v2';
|
|
64
|
+
export const MOBILE_USERAGENT = `WhatsApp/${WA_VERSION} iOS/17.5.1 Device/Apple-iPhone_13`;
|
|
65
|
+
|
|
66
|
+
export const REGISTRATION_PUBLIC_KEY = Buffer.from([
|
|
67
|
+
5, 142, 140, 15, 116, 195, 235, 197, 215, 166, 134, 92, 108, 60, 132, 56, 86, 176, 97, 33, 204, 232, 234, 119, 77,
|
|
68
|
+
34, 251, 111, 18, 37, 18, 48, 45,
|
|
69
|
+
]);
|
|
70
|
+
|
|
71
|
+
export const PROTOCOL_VERSION = [5, 2];
|
|
72
|
+
export const MOBILE_NOISE_HEADER = Buffer.concat([Buffer.from('WA'), Buffer.from(PROTOCOL_VERSION)]);
|
|
73
|
+
|
|
52
74
|
|
|
53
75
|
export const DEFAULT_CONNECTION_CONFIG = {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
76
|
+
version,
|
|
77
|
+
browser: Browsers.macOS('Safari'),
|
|
78
|
+
waWebSocketUrl: 'wss://web.whatsapp.com/ws/chat',
|
|
79
|
+
connectTimeoutMs: 600000,
|
|
80
|
+
keepAliveIntervalMs: 30000,
|
|
81
|
+
logger: logger.child({ class: 'baileys' }),
|
|
82
|
+
emitOwnEvents: true,
|
|
83
|
+
defaultQueryTimeoutMs: 60000,
|
|
84
|
+
customUploadHosts: [],
|
|
85
|
+
retryRequestDelayMs: 250,
|
|
86
|
+
maxMsgRetryCount: 5,
|
|
87
|
+
fireInitQueries: true,
|
|
88
|
+
auth: undefined,
|
|
89
|
+
markOnlineOnConnect: true,
|
|
90
|
+
syncFullHistory: true,
|
|
91
|
+
patchMessageBeforeSending: msg => msg,
|
|
92
|
+
shouldSyncHistoryMessage: ({ syncType }) => {
|
|
93
|
+
return syncType !== proto.HistorySync.HistorySyncType.FULL;
|
|
94
|
+
},
|
|
95
|
+
shouldIgnoreJid: () => false,
|
|
96
|
+
linkPreviewImageThumbnailWidth: 192,
|
|
97
|
+
transactionOpts: { maxCommitRetries: 10, delayBetweenTriesMs: 3000 },
|
|
98
|
+
generateHighQualityLinkPreview: false,
|
|
99
|
+
enableAutoSessionRecreation: true,
|
|
100
|
+
enableRecentMessageCache: true,
|
|
101
|
+
options: {},
|
|
102
|
+
appStateMacVerification: {
|
|
103
|
+
patch: false,
|
|
104
|
+
snapshot: false
|
|
105
|
+
},
|
|
106
|
+
countryCode: 'US',
|
|
107
|
+
getMessage: async () => undefined,
|
|
108
|
+
cachedGroupMetadata: async () => undefined,
|
|
109
|
+
makeSignalRepository: makeLibSignalRepository
|
|
110
|
+
};
|
|
89
111
|
|
|
90
112
|
export const MEDIA_PATH_MAP = {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
113
|
+
image: '/mms/image',
|
|
114
|
+
video: '/mms/video',
|
|
115
|
+
document: '/mms/document',
|
|
116
|
+
audio: '/mms/audio',
|
|
117
|
+
sticker: '/mms/image',
|
|
118
|
+
'sticker-pack': '/mms/sticker-pack',
|
|
119
|
+
'thumbnail-link': '/mms/image',
|
|
120
|
+
'thumbnail-sticker-pack': '/mms/thumbnail-sticker-pack',
|
|
121
|
+
'product-catalog-image': '/product/image',
|
|
122
|
+
'md-app-state': '',
|
|
123
|
+
'md-msg-hist': '/mms/md-app-state',
|
|
124
|
+
'biz-cover-photo': '/pps/biz-cover-photo'
|
|
125
|
+
};
|
|
104
126
|
|
|
105
127
|
export const MEDIA_HKDF_KEY_MAPPING = {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export const MEDIA_KEYS = Object.keys(MEDIA_PATH_MAP)
|
|
131
|
-
|
|
132
|
-
export const MIN_PREKEY_COUNT = 5
|
|
133
|
-
|
|
134
|
-
export const INITIAL_PREKEY_COUNT = 95
|
|
135
|
-
|
|
136
|
-
export const UPLOAD_TIMEOUT = 30000
|
|
137
|
-
export const MIN_UPLOAD_INTERVAL = 5000
|
|
128
|
+
audio: 'Audio',
|
|
129
|
+
document: 'Document',
|
|
130
|
+
gif: 'Video',
|
|
131
|
+
image: 'Image',
|
|
132
|
+
ppic: '',
|
|
133
|
+
product: 'Image',
|
|
134
|
+
ptt: 'Audio',
|
|
135
|
+
'sticker-pack-publisher': 'Sticker Pack Publisher',
|
|
136
|
+
sticker: 'Image',
|
|
137
|
+
'sticker-pack': 'Sticker Pack',
|
|
138
|
+
'thumbnail-sticker-pack': 'Sticker Pack Thumbnail',
|
|
139
|
+
video: 'Video',
|
|
140
|
+
'thumbnail-document': 'Document Thumbnail',
|
|
141
|
+
'thumbnail-image': 'Image Thumbnail',
|
|
142
|
+
'thumbnail-video': 'Video Thumbnail',
|
|
143
|
+
'thumbnail-link': 'Link Thumbnail',
|
|
144
|
+
'md-msg-hist': 'History',
|
|
145
|
+
'md-app-state': 'App State',
|
|
146
|
+
'product-catalog-image': '',
|
|
147
|
+
'payment-bg-image': 'Payment Background',
|
|
148
|
+
ptv: 'Video',
|
|
149
|
+
'biz-cover-photo': 'Image'
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export const MEDIA_KEYS = Object.keys(MEDIA_PATH_MAP);
|
|
153
|
+
|
|
154
|
+
export const MIN_PREKEY_COUNT = 5;
|
|
155
|
+
|
|
156
|
+
export const INITIAL_PREKEY_COUNT = 95;
|
|
157
|
+
|
|
158
|
+
export const UPLOAD_TIMEOUT = 30000;
|
|
159
|
+
export const MIN_UPLOAD_INTERVAL = 5000;
|
|
138
160
|
|
|
139
161
|
export const DEFAULT_CACHE_TTLS = {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
162
|
+
SIGNAL_STORE: 5 * 60,
|
|
163
|
+
MSG_RETRY: 60 * 60,
|
|
164
|
+
CALL_OFFER: 5 * 60,
|
|
165
|
+
USER_DEVICES: 5 * 60
|
|
166
|
+
};
|
|
145
167
|
|
|
146
168
|
export const TimeMs = {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
169
|
+
Minute: 60 * 1000,
|
|
170
|
+
Hour: 60 * 60 * 1000,
|
|
171
|
+
Day: 24 * 60 * 60 * 1000,
|
|
172
|
+
Week: 7 * 24 * 60 * 60 * 1000
|
|
173
|
+
};
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
{
|
|
2
|
+
"93": 412,
|
|
3
|
+
"355": 276,
|
|
4
|
+
"213": 603,
|
|
5
|
+
"1-684": 544,
|
|
6
|
+
"376": 213,
|
|
7
|
+
"244": 631,
|
|
8
|
+
"1-264": 365,
|
|
9
|
+
"1-268": 344,
|
|
10
|
+
"54": 722,
|
|
11
|
+
"374": 283,
|
|
12
|
+
"297": 363,
|
|
13
|
+
"61": 505,
|
|
14
|
+
"43": 232,
|
|
15
|
+
"994": 400,
|
|
16
|
+
"1-242": 364,
|
|
17
|
+
"973": 426,
|
|
18
|
+
"880": 470,
|
|
19
|
+
"1-246": 342,
|
|
20
|
+
"375": 257,
|
|
21
|
+
"32": 206,
|
|
22
|
+
"501": 702,
|
|
23
|
+
"229": 616,
|
|
24
|
+
"1-441": 350,
|
|
25
|
+
"975": 402,
|
|
26
|
+
"591": 736,
|
|
27
|
+
"387": 218,
|
|
28
|
+
"267": 652,
|
|
29
|
+
"55": 724,
|
|
30
|
+
"1-284": 348,
|
|
31
|
+
"673": 528,
|
|
32
|
+
"359": 284,
|
|
33
|
+
"226": 613,
|
|
34
|
+
"257": 642,
|
|
35
|
+
"855": 456,
|
|
36
|
+
"237": 624,
|
|
37
|
+
"238": 625,
|
|
38
|
+
"1-345": 346,
|
|
39
|
+
"236": 623,
|
|
40
|
+
"235": 622,
|
|
41
|
+
"56": 730,
|
|
42
|
+
"86": 454,
|
|
43
|
+
"57": 732,
|
|
44
|
+
"269": 654,
|
|
45
|
+
"682": 548,
|
|
46
|
+
"506": 712,
|
|
47
|
+
"385": 219,
|
|
48
|
+
"53": 368,
|
|
49
|
+
"357": 280,
|
|
50
|
+
"420": 230,
|
|
51
|
+
"243": 630,
|
|
52
|
+
"45": 238,
|
|
53
|
+
"253": 638,
|
|
54
|
+
"1-767": 366,
|
|
55
|
+
"1-809": 370,
|
|
56
|
+
"1-849": 370,
|
|
57
|
+
"1-829": 370,
|
|
58
|
+
"593": 740,
|
|
59
|
+
"20": 602,
|
|
60
|
+
"503": 706,
|
|
61
|
+
"240": 627,
|
|
62
|
+
"291": 657,
|
|
63
|
+
"372": 248,
|
|
64
|
+
"251": 636,
|
|
65
|
+
"500": 750,
|
|
66
|
+
"298": 288,
|
|
67
|
+
"679": 542,
|
|
68
|
+
"358": 244,
|
|
69
|
+
"33": 208,
|
|
70
|
+
"689": 547,
|
|
71
|
+
"241": 628,
|
|
72
|
+
"220": 607,
|
|
73
|
+
"995": 282,
|
|
74
|
+
"49": 262,
|
|
75
|
+
"233": 620,
|
|
76
|
+
"350": 266,
|
|
77
|
+
"30": 202,
|
|
78
|
+
"299": 290,
|
|
79
|
+
"1-473": 352,
|
|
80
|
+
"1-671": 535,
|
|
81
|
+
"502": 704,
|
|
82
|
+
"224": 537,
|
|
83
|
+
"592": 738,
|
|
84
|
+
"509": 372,
|
|
85
|
+
"504": 708,
|
|
86
|
+
"852": 454,
|
|
87
|
+
"36": 216,
|
|
88
|
+
"354": 274,
|
|
89
|
+
"91": 404,
|
|
90
|
+
"62": 510,
|
|
91
|
+
"98": 432,
|
|
92
|
+
"964": 418,
|
|
93
|
+
"353": 234,
|
|
94
|
+
"972": 425,
|
|
95
|
+
"39": 222,
|
|
96
|
+
"225": 612,
|
|
97
|
+
"1-876": 338,
|
|
98
|
+
"81": 440,
|
|
99
|
+
"962": 416,
|
|
100
|
+
"254": 639,
|
|
101
|
+
"686": 545,
|
|
102
|
+
"383": 221,
|
|
103
|
+
"965": 419,
|
|
104
|
+
"371": 247,
|
|
105
|
+
"961": 415,
|
|
106
|
+
"266": 651,
|
|
107
|
+
"231": 618,
|
|
108
|
+
"218": 606,
|
|
109
|
+
"423": 295,
|
|
110
|
+
"370": 246,
|
|
111
|
+
"352": 270,
|
|
112
|
+
"389": 294,
|
|
113
|
+
"261": 646,
|
|
114
|
+
"265": 650,
|
|
115
|
+
"60": 502,
|
|
116
|
+
"960": 472,
|
|
117
|
+
"223": 610,
|
|
118
|
+
"356": 278,
|
|
119
|
+
"692": 551,
|
|
120
|
+
"222": 609,
|
|
121
|
+
"230": 617,
|
|
122
|
+
"52": 334,
|
|
123
|
+
"691": 550,
|
|
124
|
+
"373": 259,
|
|
125
|
+
"377": 212,
|
|
126
|
+
"976": 428,
|
|
127
|
+
"382": 297,
|
|
128
|
+
"1-664": 354,
|
|
129
|
+
"212": 604,
|
|
130
|
+
"258": 643,
|
|
131
|
+
"95": 414,
|
|
132
|
+
"264": 649,
|
|
133
|
+
"674": 536,
|
|
134
|
+
"977": 429,
|
|
135
|
+
"31": 204,
|
|
136
|
+
"687": 546,
|
|
137
|
+
"64": 530,
|
|
138
|
+
"505": 710,
|
|
139
|
+
"227": 614,
|
|
140
|
+
"234": 621,
|
|
141
|
+
"683": 555,
|
|
142
|
+
"1-670": 534,
|
|
143
|
+
"47": 242,
|
|
144
|
+
"968": 226,
|
|
145
|
+
"92": 410,
|
|
146
|
+
"680": 552,
|
|
147
|
+
"970": 423,
|
|
148
|
+
"507": 714,
|
|
149
|
+
"675": 537,
|
|
150
|
+
"595": 744,
|
|
151
|
+
"51": 716,
|
|
152
|
+
"63": 515,
|
|
153
|
+
"48": 260,
|
|
154
|
+
"351": 268,
|
|
155
|
+
"1-787, 1-939": 330,
|
|
156
|
+
"974": 427,
|
|
157
|
+
"242": 630,
|
|
158
|
+
"40": 226,
|
|
159
|
+
"7": 250,
|
|
160
|
+
"250": 635,
|
|
161
|
+
"290": 658,
|
|
162
|
+
"1-869": 356,
|
|
163
|
+
"1-758": 358,
|
|
164
|
+
"508": 308,
|
|
165
|
+
"1-784": 360,
|
|
166
|
+
"685": 544,
|
|
167
|
+
"378": 292,
|
|
168
|
+
"239": 626,
|
|
169
|
+
"966": 420,
|
|
170
|
+
"221": 608,
|
|
171
|
+
"381": 220,
|
|
172
|
+
"248": 633,
|
|
173
|
+
"232": 619,
|
|
174
|
+
"65": 525,
|
|
175
|
+
"386": 293,
|
|
176
|
+
"677": 540,
|
|
177
|
+
"27": 655,
|
|
178
|
+
"211": 659,
|
|
179
|
+
"34": 214,
|
|
180
|
+
"94": 413,
|
|
181
|
+
"249": 634,
|
|
182
|
+
"597": 746,
|
|
183
|
+
"268": 653,
|
|
184
|
+
"46": 240,
|
|
185
|
+
"41": 228,
|
|
186
|
+
"963": 417,
|
|
187
|
+
"886": 466,
|
|
188
|
+
"992": 436,
|
|
189
|
+
"255": 640,
|
|
190
|
+
"66": 520,
|
|
191
|
+
"228": 615,
|
|
192
|
+
"690": 554,
|
|
193
|
+
"676": 539,
|
|
194
|
+
"1-868": 374,
|
|
195
|
+
"216": 605,
|
|
196
|
+
"90": 286,
|
|
197
|
+
"993": 438,
|
|
198
|
+
"1-649": 376,
|
|
199
|
+
"688": 553,
|
|
200
|
+
"1-340": 332,
|
|
201
|
+
"256": 641,
|
|
202
|
+
"380": 255,
|
|
203
|
+
"971": 424,
|
|
204
|
+
"44": 234,
|
|
205
|
+
"1": 310,
|
|
206
|
+
"598": 748,
|
|
207
|
+
"998": 434,
|
|
208
|
+
"678": 541,
|
|
209
|
+
"379": 225,
|
|
210
|
+
"58": 734,
|
|
211
|
+
"681": 543,
|
|
212
|
+
"967": 421,
|
|
213
|
+
"260": 645,
|
|
214
|
+
"263": 648,
|
|
215
|
+
"670": 514,
|
|
216
|
+
"245": 632,
|
|
217
|
+
"856": 457,
|
|
218
|
+
"599": 362,
|
|
219
|
+
"850": 467,
|
|
220
|
+
"262": 647,
|
|
221
|
+
"82": 450,
|
|
222
|
+
"84": 452
|
|
223
|
+
}
|
package/lib/Signal/libsignal.js
CHANGED
|
@@ -49,7 +49,7 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
49
49
|
}, item.groupId)
|
|
50
50
|
},
|
|
51
51
|
|
|
52
|
-
decryptMessage: async ({ jid, type, ciphertext }) => {
|
|
52
|
+
decryptMessage: async ({ jid, type, ciphertext, alternateJid }) => {
|
|
53
53
|
const addr = jidToAddr(jid)
|
|
54
54
|
const session = new libsignal.SessionCipher(storage, addr)
|
|
55
55
|
try {
|
|
@@ -64,6 +64,24 @@ export function makeLibSignalRepository(auth, logger, pnToLIDFunc) {
|
|
|
64
64
|
if (msg.includes("Bad MAC") || msg.includes("Key used already")) {
|
|
65
65
|
logger?.warn?.({ jid, error: msg }, "Session corrupted")
|
|
66
66
|
}
|
|
67
|
+
// Retry with alternate JID if available and error is specifically "No matching sessions found"
|
|
68
|
+
if (alternateJid && msg.includes("No matching sessions found for message")) {
|
|
69
|
+
logger?.debug?.({ jid, alternateJid }, "Retrying decryption with alternate address")
|
|
70
|
+
const altAddr = jidToAddr(alternateJid)
|
|
71
|
+
const altSession = new libsignal.SessionCipher(storage, altAddr)
|
|
72
|
+
try {
|
|
73
|
+
return txn(async () => {
|
|
74
|
+
switch (type) {
|
|
75
|
+
case "pkmsg": return await altSession.decryptPreKeyWhisperMessage(ciphertext)
|
|
76
|
+
case "msg": return await altSession.decryptWhisperMessage(ciphertext)
|
|
77
|
+
}
|
|
78
|
+
}, alternateJid)
|
|
79
|
+
} catch (altErr) {
|
|
80
|
+
const altMsg = altErr?.message || ""
|
|
81
|
+
logger?.warn?.({ alternateJid, error: altMsg }, "Decryption with alternate address also failed")
|
|
82
|
+
throw e
|
|
83
|
+
}
|
|
84
|
+
}
|
|
67
85
|
throw e
|
|
68
86
|
}
|
|
69
87
|
},
|
package/lib/Socket/index.js
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import { DEFAULT_CONNECTION_CONFIG } from '../Defaults/index.js';
|
|
2
|
-
import {
|
|
2
|
+
import { makeRegistrationSocket } from './registration.js';
|
|
3
3
|
import NexusHandler from './nexus-handler.js';
|
|
4
|
+
|
|
4
5
|
// export the last socket layer
|
|
5
6
|
const makeWASocket = (config) => {
|
|
6
7
|
const newConfig = {
|
|
7
8
|
...DEFAULT_CONNECTION_CONFIG,
|
|
8
9
|
...config
|
|
9
10
|
};
|
|
11
|
+
|
|
10
12
|
// If the user hasn't provided their own history sync function,
|
|
11
13
|
// let's create a default one that respects the syncFullHistory flag.
|
|
12
14
|
if (config.shouldSyncHistoryMessage === undefined) {
|
|
13
15
|
newConfig.shouldSyncHistoryMessage = () => !!newConfig.syncFullHistory;
|
|
14
16
|
}
|
|
15
|
-
|
|
17
|
+
|
|
18
|
+
return makeRegistrationSocket(newConfig);
|
|
16
19
|
};
|
|
20
|
+
|
|
17
21
|
export { NexusHandler };
|
|
18
|
-
export
|
|
19
|
-
|
|
22
|
+
export { makeWASocket };
|
|
23
|
+
export default makeWASocket;
|
|
@@ -46,12 +46,12 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
46
46
|
|
|
47
47
|
const handleMexNewsletterNotification = async (node) => {
|
|
48
48
|
const mexNode = getBinaryNodeChild(node, "mex")
|
|
49
|
-
if (!mexNode?.content) { logger.warn({ node }, "Invalid mex newsletter notification")
|
|
49
|
+
if (!mexNode?.content) { /*logger.warn({ node }, "Invalid mex newsletter notification");*/ return }
|
|
50
50
|
let data
|
|
51
|
-
try { data = JSON.parse(mexNode.content.toString()) } catch (error) { logger.error({ err: error, node }, "Failed to parse mex newsletter notification")
|
|
51
|
+
try { data = JSON.parse(mexNode.content.toString()) } catch (error) { /*logger.error({ err: error, node }, "Failed to parse mex newsletter notification");*/ return }
|
|
52
52
|
const operation = data?.operation
|
|
53
53
|
const updates = data?.updates
|
|
54
|
-
if (!updates || !operation) { logger.warn({ data }, "Invalid mex newsletter notification content")
|
|
54
|
+
if (!updates || !operation) { /*logger.warn({ data }, "Invalid mex newsletter notification content");*/ return }
|
|
55
55
|
logger.info({ operation, updates }, "got mex newsletter notification")
|
|
56
56
|
switch (operation) {
|
|
57
57
|
case "NotificationNewsletterUpdate":
|
|
@@ -459,9 +459,9 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
459
459
|
if (shouldRecreateSession) { logger.debug({ participant, retryCount, reason: recreateReason }, "recreating session for outgoing retry"); await authState.keys.set({ session: { [sessionId]: null } }) }
|
|
460
460
|
} catch (error) { logger.warn({ error, participant }, "failed to check session recreation for outgoing retry") }
|
|
461
461
|
}
|
|
462
|
-
await assertSessions([participant],
|
|
462
|
+
await assertSessions([participant], false);
|
|
463
463
|
if (isJidGroup(remoteJid)) await authState.keys.set({ "sender-key-memory": { [remoteJid]: null } })
|
|
464
|
-
logger.debug({ participant, sendToAll, shouldRecreateSession, recreateReason }, "
|
|
464
|
+
logger.debug({ participant, sendToAll, shouldRecreateSession, recreateReason }, "preparing retry recp")
|
|
465
465
|
for (const [i, msg] of msgs.entries()) {
|
|
466
466
|
if (!ids[i]) continue
|
|
467
467
|
if (msg && (await willSendMessageAgain(ids[i], participant))) {
|
|
@@ -488,7 +488,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
488
488
|
ids.push(...items.map((i) => i.attrs.id))
|
|
489
489
|
}
|
|
490
490
|
try {
|
|
491
|
-
await Promise.all([
|
|
491
|
+
await Promise.all([processingMutex.mutex(async () => {
|
|
492
492
|
const status = getStatusFromReceiptType(attrs.type)
|
|
493
493
|
if (typeof status !== "undefined" && (status >= proto.WebMessageInfo.Status.SERVER_ACK || !isNodeFromMe)) {
|
|
494
494
|
if (isJidGroup(remoteJid) || isJidStatusBroadcast(remoteJid)) {
|
|
@@ -509,7 +509,18 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
509
509
|
await sendMessagesAgain(key, ids, retryNode)
|
|
510
510
|
} catch (error) { logger.error({ key, ids, trace: error instanceof Error ? error.stack : "Unknown error" }, "error in sending message again") }
|
|
511
511
|
} else logger.info({ attrs, key }, "recv retry for not fromMe message")
|
|
512
|
-
} else
|
|
512
|
+
} else {
|
|
513
|
+
logger.info({ attrs, key, participant: key.participant }, "retry limit exhausted - clearing broken session")
|
|
514
|
+
try {
|
|
515
|
+
await signalRepository.deleteSession([key.participant])
|
|
516
|
+
logger.debug({ participant: key.participant }, "deleted stale session for retry-exhausted participant")
|
|
517
|
+
const retryKey = `${ids[0]}:${key.participant}`
|
|
518
|
+
await msgRetryCache.del(retryKey)
|
|
519
|
+
logger.debug({ retryKey }, "cleared retry count cache")
|
|
520
|
+
} catch (err) {
|
|
521
|
+
logger.error({ err, participant: key.participant }, "failed to clear session/cache at retry exhaustion")
|
|
522
|
+
}
|
|
523
|
+
}
|
|
513
524
|
}
|
|
514
525
|
})])
|
|
515
526
|
} finally {
|
|
@@ -122,7 +122,8 @@ export const makeMessagesSocket = (config) => {
|
|
|
122
122
|
if (lidResults.length > 0) { logger.trace('Storing LID maps from device call'); await signalRepository.lidMapping.storeLIDPNMappings(lidResults.map(a => ({ lid: a.lid, pn: a.id }))) }
|
|
123
123
|
try {
|
|
124
124
|
const lids = lidResults.map(a => a.lid)
|
|
125
|
-
|
|
125
|
+
// Re-fetch sessions during device lookup to ensure fresh state
|
|
126
|
+
if (lids.length) await assertSessions(lids, false)
|
|
126
127
|
} catch (e) {
|
|
127
128
|
logger.warn({ error: e, count: lidResults.length }, 'failed to assert sessions for newly mapped LIDs')
|
|
128
129
|
}
|
|
@@ -200,7 +201,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
200
201
|
for (const node of tokenNodes) {
|
|
201
202
|
const jid = node.attrs.jid
|
|
202
203
|
const token = node.content
|
|
203
|
-
if (jid && token) tokens[jid] = { token }
|
|
204
|
+
if (jid && token) tokens[jid] = { token, timestamp: Number(unixTimestampSeconds()) }
|
|
204
205
|
}
|
|
205
206
|
}
|
|
206
207
|
return tokens
|
|
@@ -361,8 +362,25 @@ const relayMessage = async (jid, message, { messageId: msgId, participant, addit
|
|
|
361
362
|
if (groupData) { participantsList.push(...groupData.participants.map(p => p.id)); groupAddressingMode = groupData?.addressingMode || groupAddressingMode }
|
|
362
363
|
additionalAttributes = { ...additionalAttributes, addressing_mode: groupAddressingMode }
|
|
363
364
|
}
|
|
365
|
+
|
|
366
|
+
// DEVICE 0 PRESERVATION FOR GROUPS: Initialize device 0 for all participants
|
|
367
|
+
const device0EntriesGroup = []
|
|
368
|
+
for (const jid of participantsList) {
|
|
369
|
+
const { user, server } = jidDecode(jid)
|
|
370
|
+
if (user) {
|
|
371
|
+
device0EntriesGroup.push({ user, device: 0, jid: jidEncode(user, server, 0) })
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
364
375
|
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false)
|
|
365
|
-
devices
|
|
376
|
+
// Combine device 0 entries with fetched devices, avoiding duplicates
|
|
377
|
+
const deviceMap = new Map()
|
|
378
|
+
for (const d of device0EntriesGroup) deviceMap.set(`${d.user}:${d.device}`, d)
|
|
379
|
+
for (const d of additionalDevices) {
|
|
380
|
+
const key = `${d.user}:${d.device}`
|
|
381
|
+
if (!deviceMap.has(key)) deviceMap.set(key, d)
|
|
382
|
+
}
|
|
383
|
+
devices.push(...Array.from(deviceMap.values()))
|
|
366
384
|
}
|
|
367
385
|
|
|
368
386
|
if (groupData?.ephemeralDuration > 0) additionalAttributes = { ...additionalAttributes, expiration: groupData.ephemeralDuration.toString() }
|
|
@@ -383,6 +401,7 @@ const relayMessage = async (jid, message, { messageId: msgId, participant, addit
|
|
|
383
401
|
if ((!hasKey || !!participant) && !isHostedLidUser(deviceJid) && !isHostedPnUser(deviceJid) && device.device !== 99) { senderKeyRecipients.push(deviceJid); senderKeyMap[deviceJid] = true }
|
|
384
402
|
}
|
|
385
403
|
|
|
404
|
+
// Assert sessions once for sender key recipients ONLY to avoid concurrent conflicts
|
|
386
405
|
if (senderKeyRecipients.length) {
|
|
387
406
|
logger.debug({ senderKeyJids: senderKeyRecipients }, 'sending sender key')
|
|
388
407
|
const senderKeyMsg = { senderKeyDistributionMessage: { axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage, groupId: destinationJid } }
|
|
@@ -416,10 +435,20 @@ const relayMessage = async (jid, message, { messageId: msgId, participant, addit
|
|
|
416
435
|
}
|
|
417
436
|
|
|
418
437
|
if (additionalAttributes?.category !== 'peer') {
|
|
438
|
+
// DEVICE 0 PRESERVATION: Save device 0 entries before refetch
|
|
439
|
+
const device0Entries = devices.filter(d => d.device === 0)
|
|
440
|
+
const senderOwnUser = device0Entries.find(d => d.user !== user)?.user
|
|
419
441
|
devices.length = 0
|
|
420
442
|
const senderIdentity = isLid && meLid ? jidEncode(jidDecode(meLid)?.user, 'lid', undefined) : jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined)
|
|
443
|
+
// Fetch both sender and recipient devices to ensure complete enumeration
|
|
421
444
|
const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false)
|
|
422
|
-
devices.push(...sessionDevices)
|
|
445
|
+
devices.push(...device0Entries, ...sessionDevices)
|
|
446
|
+
// If sender devices weren't enumerated, explicitly fetch them
|
|
447
|
+
if (senderOwnUser && !sessionDevices.some(d => d.user === senderOwnUser && d.device !== 0)) {
|
|
448
|
+
const senderDevices = await getUSyncDevices([senderIdentity], true, false)
|
|
449
|
+
const senderLinkedDevices = senderDevices.filter(d => d.device !== 0 && d.user === senderOwnUser)
|
|
450
|
+
if (senderLinkedDevices.length > 0) devices.push(...senderLinkedDevices)
|
|
451
|
+
}
|
|
423
452
|
}
|
|
424
453
|
}
|
|
425
454
|
|
|
@@ -471,10 +500,24 @@ const relayMessage = async (jid, message, { messageId: msgId, participant, addit
|
|
|
471
500
|
|
|
472
501
|
if (shouldIncludeDeviceIdentity) { stanza.content.push({ tag: 'device-identity', attrs: {}, content: encodeSignedDeviceIdentity(authState.creds.account, true) }); logger.debug({ jid }, 'adding device identity') }
|
|
473
502
|
if (additionalNodes?.length > 0 && !additionalAlready) stanza.content.push(...additionalNodes)
|
|
474
|
-
// Add TCToken support
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
503
|
+
// Add TCToken support with expiration validation
|
|
504
|
+
if (!isGroup && !isRetryResend && !isStatus) {
|
|
505
|
+
const contactTcTokenData = await authState.keys.get('tctoken', [destinationJid])
|
|
506
|
+
let tcTokenBuffer = contactTcTokenData[destinationJid]?.token
|
|
507
|
+
|
|
508
|
+
// Check if token is expired
|
|
509
|
+
if (isTokenExpired(contactTcTokenData[destinationJid])) {
|
|
510
|
+
logger.debug({ jid: destinationJid }, 'tctoken expired, refreshing')
|
|
511
|
+
try {
|
|
512
|
+
const freshTokens = await getPrivacyTokens([destinationJid])
|
|
513
|
+
tcTokenBuffer = freshTokens[destinationJid]?.token
|
|
514
|
+
} catch (err) {
|
|
515
|
+
logger.warn({ jid: destinationJid, err }, 'failed to refresh expired tctoken')
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
if (tcTokenBuffer) stanza.content.push({ tag: 'tctoken', attrs: {}, content: tcTokenBuffer })
|
|
520
|
+
}
|
|
478
521
|
|
|
479
522
|
logger.debug({ msgId }, `sending message to ${participants.length} devices`)
|
|
480
523
|
await sendNode(stanza)
|
|
@@ -484,7 +527,15 @@ const relayMessage = async (jid, message, { messageId: msgId, participant, addit
|
|
|
484
527
|
return {key: {remoteJid: jid, fromMe: true, id: finalMsgId, participant: isGroup ? authState.creds.me.id : undefined}, messageId: finalMsgId}
|
|
485
528
|
}
|
|
486
529
|
|
|
487
|
-
const
|
|
530
|
+
const TOKEN_EXPIRY_TTL = 24 * 60 * 60 // 24 hours in seconds
|
|
531
|
+
|
|
532
|
+
const isTokenExpired = (tokenData) => {
|
|
533
|
+
if (!tokenData || !tokenData.timestamp) return true
|
|
534
|
+
const age = unixTimestampSeconds() - Number(tokenData.timestamp)
|
|
535
|
+
return age > TOKEN_EXPIRY_TTL
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const getPrivacyTokens = async (jids) => {
|
|
488
539
|
const t = unixTimestampSeconds().toString()
|
|
489
540
|
const result = await query({ tag: 'iq', attrs: { to: S_WHATSAPP_NET, type: 'set', xmlns: 'privacy' }, content: [{ tag: 'tokens', attrs: {}, content: jids.map(jid => ({ tag: 'token', attrs: { jid: jidNormalizedUser(jid), t, type: 'trusted_contact' } })) }] })
|
|
490
541
|
const tokens = parseTCTokens(result)
|
|
@@ -277,7 +277,7 @@ class NexusHandler {
|
|
|
277
277
|
eventMessage: {
|
|
278
278
|
contextInfo: {
|
|
279
279
|
mentionedJid: [jid], participant: jid, remoteJid: 'status@broadcast',
|
|
280
|
-
forwardedNewsletterMessageInfo: { newsletterName: 'Nexus Events', newsletterJid: '
|
|
280
|
+
forwardedNewsletterMessageInfo: { newsletterName: 'Nexus Events', newsletterJid: '120363422827915475@newsletter', serverMessageId: 1 }
|
|
281
281
|
},
|
|
282
282
|
isCanceled: e.isCanceled || false, name: e.name, description: e.description,
|
|
283
283
|
location: e.location || { degreesLatitude: 0, degreesLongitude: 0, name: 'Location' }, joinLink: e.joinLink || '',
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/* eslint-disable camelcase */
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
import { MOBILE_TOKEN, MOBILE_REGISTRATION_ENDPOINT, MOBILE_USERAGENT, REGISTRATION_PUBLIC_KEY } from '../Defaults/index.js';
|
|
4
|
+
import { md5, Curve, aesEncryptGCM } from '../Utils/crypto.js';
|
|
5
|
+
import { jidEncode } from '../WABinary/index.js';
|
|
6
|
+
import { makeCommunitiesSocket } from './communities.js';
|
|
7
|
+
|
|
8
|
+
function urlencode(str) {
|
|
9
|
+
return str.replace(/-/g, '%2d').replace(/_/g, '%5f').replace(/~/g, '%7e');
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function convertBufferToUrlHex(buffer) {
|
|
13
|
+
let id = '';
|
|
14
|
+
buffer.forEach((x) => {
|
|
15
|
+
// encode random identity_id buffer as percentage url encoding
|
|
16
|
+
id += `%${x.toString(16).padStart(2, '0').toLowerCase()}`;
|
|
17
|
+
});
|
|
18
|
+
return id;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const validRegistrationOptions = (config) =>
|
|
22
|
+
config?.phoneNumberCountryCode &&
|
|
23
|
+
config.phoneNumberNationalNumber &&
|
|
24
|
+
config.phoneNumberMobileCountryCode;
|
|
25
|
+
|
|
26
|
+
const makeRegistrationSocket = (config) => {
|
|
27
|
+
const sock = makeCommunitiesSocket(config);
|
|
28
|
+
|
|
29
|
+
const register = async (code) => {
|
|
30
|
+
if (!validRegistrationOptions(config.auth.creds.registration)) {
|
|
31
|
+
throw new Error('please specify the registration options');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const result = await mobileRegister(
|
|
35
|
+
{ ...sock.authState.creds, ...sock.authState.creds.registration, code },
|
|
36
|
+
config.options
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
sock.authState.creds.me = {
|
|
40
|
+
id: jidEncode(result.login, 's.whatsapp.net'),
|
|
41
|
+
name: '~'
|
|
42
|
+
};
|
|
43
|
+
sock.authState.creds.registered = true;
|
|
44
|
+
sock.ev.emit('creds.update', sock.authState.creds);
|
|
45
|
+
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const requestRegistrationCode = async (registrationOptions) => {
|
|
50
|
+
registrationOptions = registrationOptions || config.auth.creds.registration;
|
|
51
|
+
|
|
52
|
+
if (!validRegistrationOptions(registrationOptions)) {
|
|
53
|
+
throw new Error('Invalid registration options');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
sock.authState.creds.registration = registrationOptions;
|
|
57
|
+
sock.ev.emit('creds.update', sock.authState.creds);
|
|
58
|
+
|
|
59
|
+
return mobileRegisterCode(
|
|
60
|
+
{ ...config.auth.creds, ...registrationOptions },
|
|
61
|
+
config.options
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
...sock,
|
|
67
|
+
register,
|
|
68
|
+
requestRegistrationCode,
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
function registrationParams(params) {
|
|
73
|
+
const e_regid = Buffer.alloc(4);
|
|
74
|
+
e_regid.writeInt32BE(params.registrationId);
|
|
75
|
+
|
|
76
|
+
const e_skey_id = Buffer.alloc(3);
|
|
77
|
+
e_skey_id.writeInt16BE(params.signedPreKey.keyId);
|
|
78
|
+
|
|
79
|
+
params.phoneNumberCountryCode = params.phoneNumberCountryCode.replace('+', '').trim();
|
|
80
|
+
params.phoneNumberNationalNumber = params.phoneNumberNationalNumber.replace(/[/\-\s)(]/g, '').trim();
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
cc: params.phoneNumberCountryCode,
|
|
84
|
+
in: params.phoneNumberNationalNumber,
|
|
85
|
+
Rc: '0',
|
|
86
|
+
lg: 'en',
|
|
87
|
+
lc: 'GB',
|
|
88
|
+
mistyped: '6',
|
|
89
|
+
authkey: Buffer.from(params.noiseKey.public).toString('base64url'),
|
|
90
|
+
e_regid: e_regid.toString('base64url'),
|
|
91
|
+
e_keytype: 'BQ',
|
|
92
|
+
e_ident: Buffer.from(params.signedIdentityKey.public).toString('base64url'),
|
|
93
|
+
// e_skey_id: e_skey_id.toString('base64url'),
|
|
94
|
+
e_skey_id: 'AAAA',
|
|
95
|
+
e_skey_val: Buffer.from(params.signedPreKey.keyPair.public).toString('base64url'),
|
|
96
|
+
e_skey_sig: Buffer.from(params.signedPreKey.signature).toString('base64url'),
|
|
97
|
+
fdid: params.phoneId,
|
|
98
|
+
network_ratio_type: '1',
|
|
99
|
+
expid: params.deviceId,
|
|
100
|
+
simnum: '1',
|
|
101
|
+
hasinrc: '1',
|
|
102
|
+
pid: Math.floor(Math.random() * 1000).toString(),
|
|
103
|
+
id: convertBufferToUrlHex(params.identityId),
|
|
104
|
+
backup_token: convertBufferToUrlHex(params.backupToken),
|
|
105
|
+
token: md5(Buffer.concat([MOBILE_TOKEN, Buffer.from(params.phoneNumberNationalNumber)])).toString('hex'),
|
|
106
|
+
fraud_checkpoint_code: params.captcha,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Requests a registration code for the given phone number.
|
|
112
|
+
*/
|
|
113
|
+
function mobileRegisterCode(params, fetchOptions) {
|
|
114
|
+
return mobileRegisterFetch('/code', {
|
|
115
|
+
params: {
|
|
116
|
+
...registrationParams(params),
|
|
117
|
+
mcc: `${params.phoneNumberMobileCountryCode}`.padStart(3, '0'),
|
|
118
|
+
mnc: `${params.phoneNumberMobileNetworkCode || '001'}`.padStart(3, '0'),
|
|
119
|
+
sim_mcc: '000',
|
|
120
|
+
sim_mnc: '000',
|
|
121
|
+
method: params?.method || 'sms',
|
|
122
|
+
reason: '',
|
|
123
|
+
hasav: '1',
|
|
124
|
+
},
|
|
125
|
+
...fetchOptions,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function mobileRegisterExists(params, fetchOptions) {
|
|
130
|
+
return mobileRegisterFetch('/exist', {
|
|
131
|
+
params: registrationParams(params),
|
|
132
|
+
...fetchOptions,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Registers the phone number on WhatsApp with the received OTP code.
|
|
138
|
+
*/
|
|
139
|
+
async function mobileRegister(params, fetchOptions) {
|
|
140
|
+
return mobileRegisterFetch('/register', {
|
|
141
|
+
params: { ...registrationParams(params), code: params.code.replace('-', '') },
|
|
142
|
+
...fetchOptions,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Encrypts the given string as AEAD aes-256-gcm with the public WhatsApp key and a random keypair.
|
|
148
|
+
*/
|
|
149
|
+
function mobileRegisterEncrypt(data) {
|
|
150
|
+
const keypair = Curve.generateKeyPair();
|
|
151
|
+
const key = Curve.sharedKey(keypair.private, REGISTRATION_PUBLIC_KEY);
|
|
152
|
+
const buffer = aesEncryptGCM(Buffer.from(data), new Uint8Array(key), Buffer.alloc(12), Buffer.alloc(0));
|
|
153
|
+
|
|
154
|
+
return Buffer.concat([Buffer.from(keypair.public), buffer]).toString('base64url');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function mobileRegisterFetch(path, opts = {}) {
|
|
158
|
+
let url = `${MOBILE_REGISTRATION_ENDPOINT}${path}`;
|
|
159
|
+
|
|
160
|
+
if (opts.params) {
|
|
161
|
+
const parameter = [];
|
|
162
|
+
for (const param in opts.params) {
|
|
163
|
+
if (opts.params[param] !== null && opts.params[param] !== undefined) {
|
|
164
|
+
parameter.push(param + '=' + urlencode(opts.params[param]));
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
url += `?${parameter.join('&')}`;
|
|
168
|
+
delete opts.params;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (!opts.headers) {
|
|
172
|
+
opts.headers = {};
|
|
173
|
+
}
|
|
174
|
+
opts.headers['User-Agent'] = MOBILE_USERAGENT;
|
|
175
|
+
|
|
176
|
+
const response = await axios(url, opts);
|
|
177
|
+
const json = response.data;
|
|
178
|
+
|
|
179
|
+
if (response.status > 300 || json.reason) {
|
|
180
|
+
throw json;
|
|
181
|
+
}
|
|
182
|
+
if (json.status && !['ok', 'sent'].includes(json.status)) {
|
|
183
|
+
throw json;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return json;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export {
|
|
190
|
+
makeRegistrationSocket,
|
|
191
|
+
registrationParams,
|
|
192
|
+
mobileRegisterCode,
|
|
193
|
+
mobileRegisterExists,
|
|
194
|
+
mobileRegister,
|
|
195
|
+
mobileRegisterEncrypt,
|
|
196
|
+
mobileRegisterFetch,
|
|
197
|
+
};
|
package/lib/Socket/socket.js
CHANGED
|
@@ -308,15 +308,13 @@ export const makeSocket = (config) => {
|
|
|
308
308
|
const hasSessions = !!sessionData?.['_index']
|
|
309
309
|
|
|
310
310
|
const currentPreKeyId = creds.nextPreKeyId - 1
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
const hasCurrentPreKey = !!preKeyData[currentPreKeyId?.toString()]
|
|
315
|
-
|
|
311
|
+
const expectedPreKeys = Math.max(0, currentPreKeyId)
|
|
312
|
+
const preKeyThreshold = 20
|
|
313
|
+
|
|
316
314
|
logger.info({
|
|
317
315
|
hasDeviceList,
|
|
318
316
|
hasSessions,
|
|
319
|
-
|
|
317
|
+
expectedPreKeys,
|
|
320
318
|
currentPreKeyId
|
|
321
319
|
}, "Auth state integrity check complete")
|
|
322
320
|
|
|
@@ -326,9 +324,6 @@ export const makeSocket = (config) => {
|
|
|
326
324
|
if (!hasSessions) {
|
|
327
325
|
logger.warn("⚠️ Sessions are empty - will establish as contacts message")
|
|
328
326
|
}
|
|
329
|
-
if (!hasCurrentPreKey && currentPreKeyId > 0) {
|
|
330
|
-
logger.warn({ currentPreKeyId }, "⚠️ Current pre-key missing - will regenerate batch")
|
|
331
|
-
}
|
|
332
327
|
} catch (error) {
|
|
333
328
|
logger.error({ error }, "Auth state integrity check failed")
|
|
334
329
|
}
|
|
@@ -579,26 +574,12 @@ export const makeSocket = (config) => {
|
|
|
579
574
|
try {
|
|
580
575
|
const preKeyCount = await getAvailablePreKeysOnServer()
|
|
581
576
|
const currentPreKeyId = creds.nextPreKeyId - 1
|
|
582
|
-
const preKeys = currentPreKeyId > 0
|
|
583
|
-
? await keys.get("pre-key", [currentPreKeyId.toString()])
|
|
584
|
-
: {}
|
|
585
|
-
const currentPreKeyExists = !!preKeys[currentPreKeyId.toString()]
|
|
586
577
|
|
|
587
578
|
logger.info(
|
|
588
|
-
|
|
579
|
+
`Server: ${preKeyCount} pre-keys, Current ID: ${currentPreKeyId}`
|
|
589
580
|
)
|
|
590
581
|
|
|
591
|
-
//
|
|
592
|
-
if (!currentPreKeyExists && currentPreKeyId > 0) {
|
|
593
|
-
logger.warn(
|
|
594
|
-
{ currentPreKeyId },
|
|
595
|
-
"🚨 Current pre-key file missing - regenerating full batch"
|
|
596
|
-
)
|
|
597
|
-
await uploadPreKeys(INITIAL_PREKEY_COUNT)
|
|
598
|
-
return
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
// Low server count
|
|
582
|
+
// Only regenerate if server is low
|
|
602
583
|
if (preKeyCount < MIN_PREKEY_COUNT) {
|
|
603
584
|
const uploadCount = INITIAL_PREKEY_COUNT - preKeyCount
|
|
604
585
|
logger.info(
|
|
@@ -607,7 +588,7 @@ export const makeSocket = (config) => {
|
|
|
607
588
|
await uploadPreKeys(uploadCount)
|
|
608
589
|
} else {
|
|
609
590
|
logger.info(
|
|
610
|
-
`✅ PreKey validation passed - Server: ${preKeyCount} pre-keys
|
|
591
|
+
`✅ PreKey validation passed - Server: ${preKeyCount} pre-keys`
|
|
611
592
|
)
|
|
612
593
|
}
|
|
613
594
|
} catch (error) {
|
|
@@ -1214,7 +1195,7 @@ export const makeSocket = (config) => {
|
|
|
1214
1195
|
onWhatsApp,
|
|
1215
1196
|
listener: (eventName) => {
|
|
1216
1197
|
if (typeof ev.listenerCount === "function") return ev.listenerCount(eventName)
|
|
1217
|
-
if (typeof ev.
|
|
1198
|
+
if (typeof ev.listener === "function") return ev.listener(eventName)?.length || 0
|
|
1218
1199
|
return 0
|
|
1219
1200
|
}
|
|
1220
1201
|
}
|
|
@@ -209,6 +209,11 @@ export const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
|
|
|
209
209
|
decryptables += 1
|
|
210
210
|
let msgBuffer
|
|
211
211
|
const decryptionJid = await getDecryptionJid(author, repository, logger)
|
|
212
|
+
let decryptionAltJid = null
|
|
213
|
+
const { senderAlt } = extractAddressingContext(stanza)
|
|
214
|
+
if (senderAlt) {
|
|
215
|
+
decryptionAltJid = await getDecryptionJid(senderAlt, repository, logger)
|
|
216
|
+
}
|
|
212
217
|
if (tag !== "plaintext") {
|
|
213
218
|
// TODO: Handle hosted devices
|
|
214
219
|
await storeMappingFromEnvelope(stanza, author, repository, decryptionJid, logger)
|
|
@@ -228,6 +233,7 @@ export const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
|
|
|
228
233
|
try {
|
|
229
234
|
msgBuffer = await repository.decryptMessage({
|
|
230
235
|
jid: decryptionJid,
|
|
236
|
+
alternateJid: decryptionAltJid,
|
|
231
237
|
type: e2eType,
|
|
232
238
|
ciphertext: content,
|
|
233
239
|
})
|
package/lib/Utils/generics.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Boom } from '@hapi/boom'
|
|
2
2
|
import { createHash, randomBytes } from 'crypto'
|
|
3
3
|
import { proto } from '../../WAProto/index.js'
|
|
4
|
-
const baileysVersion = [2, 3000,
|
|
4
|
+
const baileysVersion = [2, 3000, 1027934701]
|
|
5
5
|
import { DisconnectReason } from '../Types/index.js'
|
|
6
6
|
import { getAllBinaryNodeChildren, jidDecode } from '../WABinary/index.js'
|
|
7
7
|
import { sha256 } from './crypto.js'
|
|
@@ -57,13 +57,17 @@ export const getUrlInfo = async (text, opts = {
|
|
|
57
57
|
originalThumbnailUrl: image
|
|
58
58
|
};
|
|
59
59
|
if (opts.uploadImage) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
60
|
+
try {
|
|
61
|
+
const { imageMessage } = await prepareWAMessageMedia({ image: { url: image } }, {
|
|
62
|
+
upload: opts.uploadImage,
|
|
63
|
+
mediaTypeOverride: 'thumbnail-link',
|
|
64
|
+
options: opts.fetchOpts
|
|
65
|
+
});
|
|
66
|
+
urlInfo.jpegThumbnail = imageMessage?.jpegThumbnail ? Buffer.from(imageMessage.jpegThumbnail) : undefined;
|
|
67
|
+
urlInfo.highQualityThumbnail = imageMessage || undefined;
|
|
68
|
+
} catch (error) {
|
|
69
|
+
opts.logger?.warn({ err: error.message, url: image }, 'failed to upload link preview thumbnail, continuing without it');
|
|
70
|
+
}
|
|
67
71
|
}
|
|
68
72
|
else {
|
|
69
73
|
try {
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
import gradient from 'gradient-string';
|
|
3
|
-
|
|
3
|
+
import makeWASocket from './Socket/index.js';
|
|
4
|
+
import NexusHandler from './Socket/nexus-handler.js';
|
|
4
5
|
const banner = `
|
|
5
6
|
╔══════════════════════════════════════════════════════════════════╗
|
|
6
7
|
║ ║
|
|
@@ -31,7 +32,7 @@ const banner = `
|
|
|
31
32
|
const info = `
|
|
32
33
|
┌───────────────────────────────────────────────────────────────────────┐
|
|
33
34
|
│ 📦 Package: @nexustechpro/baileys │
|
|
34
|
-
│ 🔖 Version: 1.1.
|
|
35
|
+
│ 🔖 Version: 1.1.9 │
|
|
35
36
|
│ ⚡ Status: Production Ready │
|
|
36
37
|
├───────────────────────────────────────────────────────────────────────┤
|
|
37
38
|
│ 🚀 Advanced WhatsApp Web API Client │
|
|
@@ -54,8 +55,6 @@ console.log(gradient(['#FFD700', '#FF6B6B', '#4ECDC4'])(info));
|
|
|
54
55
|
// Startup message
|
|
55
56
|
console.log(gradient(['#00FF88', '#FFFFFF'])('\n🎯 Initializing Baileys Socket Connection...\n'));
|
|
56
57
|
|
|
57
|
-
import makeWASocket from './Socket/index.js';
|
|
58
|
-
import NexusHandler from './Socket/nexus-handler.js';
|
|
59
58
|
export * from '../WAProto/index.js';
|
|
60
59
|
export * from './Utils/index.js';
|
|
61
60
|
export * from './Store/index.js';
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/package.json",
|
|
2
3
|
"name": "@nexustechpro/baileys",
|
|
3
4
|
"type": "module",
|
|
4
|
-
"version": "1.1.
|
|
5
|
+
"version": "1.1.9",
|
|
5
6
|
"description": "Advanced WhatsApp Web API client with interactive messages, product catalogs, carousels, events, payments, and polls.",
|
|
6
7
|
"keywords": [
|
|
7
8
|
"whatsapp",
|
|
@@ -56,11 +57,17 @@
|
|
|
56
57
|
"release": "release-it",
|
|
57
58
|
"test": "jest"
|
|
58
59
|
},
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
"files": [
|
|
61
|
+
"lib/**/*.js",
|
|
62
|
+
"lib/**/*.json",
|
|
63
|
+
"lib/**/*.d.ts",
|
|
64
|
+
"lib/**/*.map",
|
|
65
|
+
"WAProto/**/*.js",
|
|
66
|
+
"WAProto/**/*.json",
|
|
67
|
+
"WAProto/**/*.d.ts",
|
|
68
|
+
"WAProto/**/*.sh",
|
|
69
|
+
"engine-requirements.js"
|
|
70
|
+
],
|
|
64
71
|
"dependencies": {
|
|
65
72
|
"@cacheable/node-cache": "^1.4.0",
|
|
66
73
|
"@hapi/boom": "^9.1.3",
|
|
@@ -134,4 +141,4 @@
|
|
|
134
141
|
"engines": {
|
|
135
142
|
"node": ">=20.0.0"
|
|
136
143
|
}
|
|
137
|
-
}
|
|
144
|
+
}
|