violetics 7.0.1-alpha → 7.0.2-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +3 -2
- package/README.md +1001 -232
- package/WAProto/index.js +75379 -142631
- package/engine-requirements.js +11 -8
- package/lib/Defaults/index.js +132 -146
- package/lib/Signal/Group/ciphertext-message.js +2 -6
- package/lib/Signal/Group/group-session-builder.js +7 -42
- package/lib/Signal/Group/group_cipher.js +37 -52
- package/lib/Signal/Group/index.js +11 -57
- package/lib/Signal/Group/keyhelper.js +7 -45
- package/lib/Signal/Group/sender-chain-key.js +7 -16
- package/lib/Signal/Group/sender-key-distribution-message.js +8 -12
- package/lib/Signal/Group/sender-key-message.js +9 -13
- package/lib/Signal/Group/sender-key-name.js +2 -6
- package/lib/Signal/Group/sender-key-record.js +9 -22
- package/lib/Signal/Group/sender-key-state.js +27 -43
- package/lib/Signal/Group/sender-message-key.js +4 -8
- package/lib/Signal/libsignal.js +319 -94
- package/lib/Signal/lid-mapping.js +224 -139
- package/lib/Socket/Client/index.js +2 -19
- package/lib/Socket/Client/types.js +10 -0
- package/lib/Socket/Client/websocket.js +53 -0
- package/lib/Socket/business.js +162 -44
- package/lib/Socket/chats.js +477 -418
- package/lib/Socket/communities.js +430 -0
- package/lib/Socket/groups.js +110 -99
- package/lib/Socket/index.js +10 -10
- package/lib/Socket/messages-recv.js +884 -561
- package/lib/Socket/messages-send.js +859 -428
- package/lib/Socket/mex.js +41 -0
- package/lib/Socket/newsletter.js +195 -390
- package/lib/Socket/socket.js +465 -315
- package/lib/Store/index.js +3 -10
- package/lib/Store/make-in-memory-store.js +73 -79
- package/lib/Store/make-ordered-dictionary.js +4 -7
- package/lib/Store/object-repository.js +2 -6
- package/lib/Types/Auth.js +1 -2
- package/lib/Types/Bussines.js +1 -0
- package/lib/Types/Call.js +1 -2
- package/lib/Types/Chat.js +7 -4
- package/lib/Types/Contact.js +1 -2
- package/lib/Types/Events.js +1 -2
- package/lib/Types/GroupMetadata.js +1 -2
- package/lib/Types/Label.js +2 -5
- package/lib/Types/LabelAssociation.js +2 -5
- package/lib/Types/Message.js +17 -9
- package/lib/Types/Newsletter.js +33 -38
- package/lib/Types/Product.js +1 -2
- package/lib/Types/Signal.js +1 -2
- package/lib/Types/Socket.js +2 -2
- package/lib/Types/State.js +12 -2
- package/lib/Types/USync.js +1 -2
- package/lib/Types/index.js +14 -31
- package/lib/Utils/auth-utils.js +228 -152
- package/lib/Utils/browser-utils.js +28 -0
- package/lib/Utils/business.js +66 -70
- package/lib/Utils/chat-utils.js +331 -249
- package/lib/Utils/crypto.js +57 -91
- package/lib/Utils/decode-wa-message.js +168 -84
- package/lib/Utils/event-buffer.js +138 -80
- package/lib/Utils/generics.js +180 -297
- package/lib/Utils/history.js +83 -49
- package/lib/Utils/identity-change-handler.js +48 -0
- package/lib/Utils/index.js +19 -33
- package/lib/Utils/link-preview.js +14 -23
- package/lib/Utils/logger.js +2 -7
- package/lib/Utils/lt-hash.js +2 -46
- package/lib/Utils/make-mutex.js +24 -47
- package/lib/Utils/message-retry-manager.js +224 -0
- package/lib/Utils/messages-media.js +501 -496
- package/lib/Utils/messages.js +1428 -362
- package/lib/Utils/noise-handler.js +145 -100
- package/lib/Utils/pre-key-manager.js +105 -0
- package/lib/Utils/process-message.js +356 -150
- package/lib/Utils/reporting-utils.js +257 -0
- package/lib/Utils/signal.js +78 -73
- package/lib/Utils/sync-action-utils.js +47 -0
- package/lib/Utils/tc-token-utils.js +17 -0
- package/lib/Utils/use-multi-file-auth-state.js +35 -45
- package/lib/Utils/validate-connection.js +91 -107
- package/lib/WABinary/constants.js +1300 -1304
- package/lib/WABinary/decode.js +26 -48
- package/lib/WABinary/encode.js +109 -155
- package/lib/WABinary/generic-utils.js +161 -149
- package/lib/WABinary/index.js +5 -21
- package/lib/WABinary/jid-utils.js +73 -40
- package/lib/WABinary/types.js +1 -2
- package/lib/WAM/BinaryInfo.js +2 -6
- package/lib/WAM/constants.js +19070 -11568
- package/lib/WAM/encode.js +17 -23
- package/lib/WAM/index.js +3 -19
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +8 -12
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +11 -15
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +9 -13
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +9 -14
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +20 -23
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +13 -9
- package/lib/WAUSync/Protocols/index.js +4 -20
- package/lib/WAUSync/USyncQuery.js +40 -36
- package/lib/WAUSync/USyncUser.js +2 -6
- package/lib/WAUSync/index.js +3 -19
- package/lib/index.js +11 -44
- package/package.json +74 -107
- package/lib/Defaults/baileys-version.json +0 -3
- package/lib/Defaults/phonenumber-mcc.json +0 -223
- package/lib/Signal/Group/queue-job.js +0 -57
- package/lib/Socket/Client/abstract-socket-client.js +0 -13
- package/lib/Socket/Client/mobile-socket-client.js +0 -65
- package/lib/Socket/Client/web-socket-client.js +0 -118
- package/lib/Socket/groupStatus.js +0 -637
- package/lib/Socket/registration.js +0 -166
- package/lib/Socket/usync.js +0 -70
- package/lib/Store/make-cache-manager-store.js +0 -83
- package/lib/Utils/baileys-event-stream.js +0 -63
package/lib/Socket/chats.js
CHANGED
|
@@ -1,30 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const WABinary_1 = require("../WABinary");
|
|
15
|
-
const socket_1 = require("./socket");
|
|
16
|
-
const WAUSync_1 = require("../WAUSync");
|
|
17
|
-
const usync_1 = require("./usync");
|
|
1
|
+
import NodeCache from '@cacheable/node-cache';
|
|
2
|
+
import { Boom } from '@hapi/boom';
|
|
3
|
+
import { proto } from '../../WAProto/index.js';
|
|
4
|
+
import { DEFAULT_CACHE_TTLS, PROCESSABLE_HISTORY_TYPES } from '../Defaults/index.js';
|
|
5
|
+
import { ALL_WA_PATCH_NAMES } from '../Types/index.js';
|
|
6
|
+
import { SyncState } from '../Types/State.js';
|
|
7
|
+
import { chatModificationToAppPatch, decodePatches, decodeSyncdSnapshot, encodeSyncdPatch, extractSyncdPatches, generateProfilePicture, getHistoryMsg, newLTHashState, processSyncAction } from '../Utils/index.js';
|
|
8
|
+
import { makeMutex } from '../Utils/make-mutex.js';
|
|
9
|
+
import processMessage from '../Utils/process-message.js';
|
|
10
|
+
import { buildTcTokenFromJid } from '../Utils/tc-token-utils.js';
|
|
11
|
+
import { getBinaryNodeChild, getBinaryNodeChildren, isLidUser, isPnUser, jidDecode, jidNormalizedUser, reduceBinaryNodeToDictionary, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
12
|
+
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
13
|
+
import { makeSocket } from './socket.js';
|
|
18
14
|
const MAX_SYNC_ATTEMPTS = 2;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const {
|
|
15
|
+
// Lia@Note 08-02-26 --- I know it's not efficient for RSS ಥ‿ಥ
|
|
16
|
+
const USER_ID_CACHE = new Map();
|
|
17
|
+
export const makeChatsSocket = (config) => {
|
|
18
|
+
const { logger, markOnlineOnConnect, fireInitQueries, appStateMacVerification, shouldIgnoreJid, shouldSyncHistoryMessage, getMessage } = config;
|
|
19
|
+
const sock = makeSocket(config);
|
|
20
|
+
const { ev, ws, authState, generateMessageTag, sendNode, query, signalRepository, onUnexpectedError, sendUnifiedSession } = sock;
|
|
23
21
|
let privacySettings;
|
|
24
|
-
let
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
let syncState = SyncState.Connecting;
|
|
23
|
+
/** this mutex ensures that messages are processed in order */
|
|
24
|
+
const messageMutex = makeMutex();
|
|
25
|
+
/** this mutex ensures that receipts are processed in order */
|
|
26
|
+
const receiptMutex = makeMutex();
|
|
27
|
+
/** this mutex ensures that app state patches are processed in order */
|
|
28
|
+
const appStatePatchMutex = makeMutex();
|
|
29
|
+
/** this mutex ensures that notifications are processed in order */
|
|
30
|
+
const notificationMutex = makeMutex();
|
|
31
|
+
// Timeout for AwaitingInitialSync state
|
|
32
|
+
let awaitingSyncTimeout;
|
|
33
|
+
const placeholderResendCache = config.placeholderResendCache ||
|
|
34
|
+
new NodeCache({
|
|
35
|
+
stdTTL: DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
|
|
36
|
+
useClones: false
|
|
37
|
+
});
|
|
38
|
+
if (!config.placeholderResendCache) {
|
|
39
|
+
config.placeholderResendCache = placeholderResendCache;
|
|
40
|
+
}
|
|
28
41
|
/** helper function to fetch the given app state sync key */
|
|
29
42
|
const getAppStateSyncKey = async (keyId) => {
|
|
30
43
|
const { [keyId]: key } = await authState.keys.get('app-state-sync-key', [keyId]);
|
|
@@ -36,14 +49,12 @@ const makeChatsSocket = (config) => {
|
|
|
36
49
|
tag: 'iq',
|
|
37
50
|
attrs: {
|
|
38
51
|
xmlns: 'privacy',
|
|
39
|
-
to:
|
|
52
|
+
to: S_WHATSAPP_NET,
|
|
40
53
|
type: 'get'
|
|
41
54
|
},
|
|
42
|
-
content: [
|
|
43
|
-
{ tag: 'privacy', attrs: {} }
|
|
44
|
-
]
|
|
55
|
+
content: [{ tag: 'privacy', attrs: {} }]
|
|
45
56
|
});
|
|
46
|
-
privacySettings =
|
|
57
|
+
privacySettings = reduceBinaryNodeToDictionary(content?.[0], 'category');
|
|
47
58
|
}
|
|
48
59
|
return privacySettings;
|
|
49
60
|
};
|
|
@@ -53,10 +64,11 @@ const makeChatsSocket = (config) => {
|
|
|
53
64
|
tag: 'iq',
|
|
54
65
|
attrs: {
|
|
55
66
|
xmlns: 'privacy',
|
|
56
|
-
to:
|
|
67
|
+
to: S_WHATSAPP_NET,
|
|
57
68
|
type: 'set'
|
|
58
69
|
},
|
|
59
|
-
content: [
|
|
70
|
+
content: [
|
|
71
|
+
{
|
|
60
72
|
tag: 'privacy',
|
|
61
73
|
attrs: {},
|
|
62
74
|
content: [
|
|
@@ -65,9 +77,16 @@ const makeChatsSocket = (config) => {
|
|
|
65
77
|
attrs: { name, value }
|
|
66
78
|
}
|
|
67
79
|
]
|
|
68
|
-
}
|
|
80
|
+
}
|
|
81
|
+
]
|
|
69
82
|
});
|
|
70
83
|
};
|
|
84
|
+
const updateMessagesPrivacy = async (value) => {
|
|
85
|
+
await privacyQuery('messages', value);
|
|
86
|
+
};
|
|
87
|
+
const updateCallPrivacy = async (value) => {
|
|
88
|
+
await privacyQuery('calladd', value);
|
|
89
|
+
};
|
|
71
90
|
const updateLastSeenPrivacy = async (value) => {
|
|
72
91
|
await privacyQuery('last', value);
|
|
73
92
|
};
|
|
@@ -86,258 +105,128 @@ const makeChatsSocket = (config) => {
|
|
|
86
105
|
const updateGroupsAddPrivacy = async (value) => {
|
|
87
106
|
await privacyQuery('groupadd', value);
|
|
88
107
|
};
|
|
89
|
-
/** check whether your WhatsApp account is blocked or not */
|
|
90
|
-
const checkWhatsApp = async (jid) => {
|
|
91
|
-
if (!jid) {
|
|
92
|
-
throw new Error('enter jid');
|
|
93
|
-
}
|
|
94
|
-
let resultData = {
|
|
95
|
-
isBanned: false,
|
|
96
|
-
isNeedOfficialWa: false,
|
|
97
|
-
number: jid
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
let phoneNumber = jid;
|
|
101
|
-
if (phoneNumber.includes('@')) {
|
|
102
|
-
phoneNumber = phoneNumber.split('@')[0];
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
phoneNumber = phoneNumber.replace(/[^\d+]/g, '');
|
|
106
|
-
if (!phoneNumber.startsWith('+')) {
|
|
107
|
-
if (phoneNumber.startsWith('0')) {
|
|
108
|
-
phoneNumber = phoneNumber.substring(1);
|
|
109
|
-
}
|
|
110
|
-
if (!phoneNumber.startsWith('62') && phoneNumber.length > 0) {
|
|
111
|
-
phoneNumber = '62' + phoneNumber;
|
|
112
|
-
}
|
|
113
|
-
if (!phoneNumber.startsWith('+') && phoneNumber.length > 0) {
|
|
114
|
-
phoneNumber = '+' + phoneNumber;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const { parsePhoneNumber } = require('libphonenumber-js');
|
|
119
|
-
const parsedNumber = parsePhoneNumber(phoneNumber);
|
|
120
|
-
const countryCode = parsedNumber.countryCallingCode;
|
|
121
|
-
const nationalNumber = parsedNumber.nationalNumber;
|
|
122
|
-
|
|
123
|
-
try {
|
|
124
|
-
// mobileRegisterExists() hits /exist endpoint — NO SMS is ever sent.
|
|
125
|
-
// It checks account status and returns ban errors (appeal_token, custom_block_screen)
|
|
126
|
-
// same as the /code endpoint would, but without triggering OTP delivery.
|
|
127
|
-
const { mobileRegisterExists } = require('./registration');
|
|
128
|
-
await mobileRegisterExists({
|
|
129
|
-
...authState.creds,
|
|
130
|
-
phoneNumberCountryCode: countryCode,
|
|
131
|
-
phoneNumberNationalNumber: nationalNumber,
|
|
132
|
-
phoneNumberMobileCountryCode: '510',
|
|
133
|
-
phoneNumberMobileNetworkCode: '10',
|
|
134
|
-
}, config.options);
|
|
135
|
-
return JSON.stringify(resultData, null, 2);
|
|
136
|
-
} catch (err) {
|
|
137
|
-
if (err?.appeal_token) {
|
|
138
|
-
resultData.isBanned = true;
|
|
139
|
-
resultData.data = {
|
|
140
|
-
violation_type: err.violation_type || null,
|
|
141
|
-
in_app_ban_appeal: err.in_app_ban_appeal || null,
|
|
142
|
-
appeal_token: err.appeal_token || null,
|
|
143
|
-
};
|
|
144
|
-
} else if (err?.custom_block_screen || err?.reason === 'blocked') {
|
|
145
|
-
resultData.isNeedOfficialWa = true;
|
|
146
|
-
}
|
|
147
|
-
return JSON.stringify(resultData, null, 2);
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
// 60%
|
|
151
|
-
const reqPairing = async (number, count, config) => {
|
|
152
|
-
const { makeSocket } = require("./socket");
|
|
153
|
-
const socket = makeSocket(config);
|
|
154
|
-
const phoneNumber = number.replace(/[^0-9]/g, '');
|
|
155
|
-
for (let i = 0; i < count; i++) {
|
|
156
|
-
const code = await socket.requestPairingCode(phoneNumber, "0000XXXX");
|
|
157
|
-
const formattedCode = code?.match(/.{1,4}/g)?.join('-') || code;
|
|
158
|
-
console.log(`Spam ${i + 1}/${count} | ${formattedCode}`);
|
|
159
|
-
if (i < count - 1) {
|
|
160
|
-
await new Promise(resolve => setTimeout(resolve, 30000));
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
108
|
const updateDefaultDisappearingMode = async (duration) => {
|
|
165
109
|
await query({
|
|
166
110
|
tag: 'iq',
|
|
167
111
|
attrs: {
|
|
168
112
|
xmlns: 'disappearing_mode',
|
|
169
|
-
to:
|
|
113
|
+
to: S_WHATSAPP_NET,
|
|
170
114
|
type: 'set'
|
|
171
115
|
},
|
|
172
|
-
content: [
|
|
116
|
+
content: [
|
|
117
|
+
{
|
|
173
118
|
tag: 'disappearing_mode',
|
|
174
119
|
attrs: {
|
|
175
120
|
duration: duration.toString()
|
|
176
121
|
}
|
|
177
|
-
}
|
|
122
|
+
}
|
|
123
|
+
]
|
|
178
124
|
});
|
|
179
125
|
};
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const result = await query({
|
|
126
|
+
const getBotListV2 = async () => {
|
|
127
|
+
const resp = await query({
|
|
183
128
|
tag: 'iq',
|
|
184
129
|
attrs: {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
130
|
+
xmlns: 'bot',
|
|
131
|
+
to: S_WHATSAPP_NET,
|
|
132
|
+
type: 'get'
|
|
188
133
|
},
|
|
189
134
|
content: [
|
|
190
135
|
{
|
|
191
|
-
tag: '
|
|
136
|
+
tag: 'bot',
|
|
192
137
|
attrs: {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
last: 'true',
|
|
196
|
-
index: '0',
|
|
197
|
-
context: 'interactive',
|
|
198
|
-
},
|
|
199
|
-
content: [
|
|
200
|
-
{
|
|
201
|
-
tag: 'query',
|
|
202
|
-
attrs: {},
|
|
203
|
-
content: [queryNode]
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
tag: 'list',
|
|
207
|
-
attrs: {},
|
|
208
|
-
content: userNodes
|
|
209
|
-
}
|
|
210
|
-
]
|
|
138
|
+
v: '2'
|
|
139
|
+
}
|
|
211
140
|
}
|
|
212
|
-
]
|
|
213
|
-
});
|
|
214
|
-
const usyncNode = (0, WABinary_1.getBinaryNodeChild)(result, 'usync');
|
|
215
|
-
const listNode = (0, WABinary_1.getBinaryNodeChild)(usyncNode, 'list');
|
|
216
|
-
const users = (0, WABinary_1.getBinaryNodeChildren)(listNode, 'user');
|
|
217
|
-
return users;
|
|
218
|
-
};
|
|
219
|
-
const getBusinessProfile = async (jid) => {
|
|
220
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
221
|
-
const results = await query({
|
|
222
|
-
tag: 'iq',
|
|
223
|
-
attrs: {
|
|
224
|
-
to: 's.whatsapp.net',
|
|
225
|
-
xmlns: 'w:biz',
|
|
226
|
-
type: 'get'
|
|
227
|
-
},
|
|
228
|
-
content: [{
|
|
229
|
-
tag: 'business_profile',
|
|
230
|
-
attrs: { v: '244' },
|
|
231
|
-
content: [{
|
|
232
|
-
tag: 'profile',
|
|
233
|
-
attrs: { jid }
|
|
234
|
-
}]
|
|
235
|
-
}]
|
|
141
|
+
]
|
|
236
142
|
});
|
|
237
|
-
const
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
const businessHoursConfig = businessHours ?
|
|
247
|
-
(0, WABinary_1.getBinaryNodeChildren)(businessHours, 'business_hours_config') :
|
|
248
|
-
undefined;
|
|
249
|
-
const websiteStr = (_a = website === null || website === void 0 ? void 0 : website.content) === null || _a === void 0 ? void 0 : _a.toString();
|
|
250
|
-
return {
|
|
251
|
-
wid: (_b = profiles.attrs) === null || _b === void 0 ? void 0 : _b.jid,
|
|
252
|
-
address: (_c = address === null || address === void 0 ? void 0 : address.content) === null || _c === void 0 ? void 0 : _c.toString(),
|
|
253
|
-
description: ((_d = description === null || description === void 0 ? void 0 : description.content) === null || _d === void 0 ? void 0 : _d.toString()) || '',
|
|
254
|
-
website: websiteStr ? [websiteStr] : [],
|
|
255
|
-
email: (_e = email === null || email === void 0 ? void 0 : email.content) === null || _e === void 0 ? void 0 : _e.toString(),
|
|
256
|
-
category: (_f = category === null || category === void 0 ? void 0 : category.content) === null || _f === void 0 ? void 0 : _f.toString(),
|
|
257
|
-
'business_hours': {
|
|
258
|
-
timezone: (_g = businessHours === null || businessHours === void 0 ? void 0 : businessHours.attrs) === null || _g === void 0 ? void 0 : _g.timezone,
|
|
259
|
-
'business_config': businessHoursConfig === null || businessHoursConfig === void 0 ? void 0 : businessHoursConfig.map(({ attrs }) => attrs)
|
|
143
|
+
const botNode = getBinaryNodeChild(resp, 'bot');
|
|
144
|
+
const botList = [];
|
|
145
|
+
for (const section of getBinaryNodeChildren(botNode, 'section')) {
|
|
146
|
+
if (section.attrs.type === 'all') {
|
|
147
|
+
for (const bot of getBinaryNodeChildren(section, 'bot')) {
|
|
148
|
+
botList.push({
|
|
149
|
+
jid: bot.attrs.jid,
|
|
150
|
+
personaId: bot.attrs['persona_id']
|
|
151
|
+
});
|
|
260
152
|
}
|
|
261
|
-
}
|
|
153
|
+
}
|
|
262
154
|
}
|
|
155
|
+
return botList;
|
|
263
156
|
};
|
|
264
|
-
const
|
|
265
|
-
const usyncQuery = new
|
|
266
|
-
.withContactProtocol()
|
|
267
|
-
.withLIDProtocol();
|
|
268
|
-
|
|
157
|
+
const fetchStatus = async (...jids) => {
|
|
158
|
+
const usyncQuery = new USyncQuery().withStatusProtocol();
|
|
269
159
|
for (const jid of jids) {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
if (results) {
|
|
276
|
-
const verifiedResults = await Promise.all(
|
|
277
|
-
results.list
|
|
278
|
-
.filter((a) => !!a.contact)
|
|
279
|
-
.map(async ({ contact, id, lid }) => {
|
|
280
|
-
try {
|
|
281
|
-
const businessProfile = await getBusinessProfile(id);
|
|
282
|
-
const isBusiness = businessProfile && Object.keys(businessProfile).length > 0;
|
|
283
|
-
if (isBusiness) {
|
|
284
|
-
const { wid, ...businessInfo } = businessProfile;
|
|
285
|
-
|
|
286
|
-
return {
|
|
287
|
-
jid: id,
|
|
288
|
-
exists: true,
|
|
289
|
-
lid: lid,
|
|
290
|
-
status: 'business',
|
|
291
|
-
businessInfo: businessInfo
|
|
292
|
-
};
|
|
293
|
-
} else {
|
|
294
|
-
return {
|
|
295
|
-
jid: id,
|
|
296
|
-
exists: true,
|
|
297
|
-
lid: lid,
|
|
298
|
-
status: 'regular'
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
} catch (error) {
|
|
302
|
-
return {
|
|
303
|
-
jid: id,
|
|
304
|
-
exists: true,
|
|
305
|
-
lid: lid,
|
|
306
|
-
status: error
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
})
|
|
310
|
-
);
|
|
311
|
-
return verifiedResults;
|
|
160
|
+
usyncQuery.withUser(new USyncUser().withId(jid));
|
|
161
|
+
}
|
|
162
|
+
const result = await sock.executeUSyncQuery(usyncQuery);
|
|
163
|
+
if (result) {
|
|
164
|
+
return result.list;
|
|
312
165
|
}
|
|
313
166
|
};
|
|
314
|
-
const
|
|
315
|
-
const
|
|
167
|
+
const fetchDisappearingDuration = async (...jids) => {
|
|
168
|
+
const usyncQuery = new USyncQuery().withDisappearingModeProtocol();
|
|
169
|
+
for (const jid of jids) {
|
|
170
|
+
usyncQuery.withUser(new USyncUser().withId(jid));
|
|
171
|
+
}
|
|
172
|
+
const result = await sock.executeUSyncQuery(usyncQuery);
|
|
316
173
|
if (result) {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
174
|
+
return result.list;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
// Lia@Note 06-02-26 --- Quick helper only. This function exists solely for faster lookup with caching.
|
|
178
|
+
const findUserId = async (pnLid) => {
|
|
179
|
+
const cachedId = USER_ID_CACHE.get(pnLid);
|
|
180
|
+
if (cachedId) {
|
|
181
|
+
return cachedId;
|
|
182
|
+
}
|
|
183
|
+
const userId = {};
|
|
184
|
+
if (isPnUser(pnLid)) {
|
|
185
|
+
userId.phoneNumber = pnLid;
|
|
186
|
+
userId.lid = (await signalRepository.lidMapping.getLIDsForPNs([pnLid]))?.[0]?.lid;
|
|
187
|
+
if (!userId.lid) {
|
|
188
|
+
userId.lid = 'id-not-found';
|
|
189
|
+
return userId; // Lia@Note 06-02-26 --- Early return to skip caching for non-existent ID
|
|
190
|
+
}
|
|
322
191
|
}
|
|
192
|
+
else if (isLidUser(pnLid)) {
|
|
193
|
+
userId.lid = pnLid;
|
|
194
|
+
userId.phoneNumber = (await signalRepository.lidMapping.getPNsForLIDs([pnLid]))?.[0]?.pn;
|
|
195
|
+
if (!userId.phoneNumber) {
|
|
196
|
+
userId.phoneNumber = 'id-not-found';
|
|
197
|
+
return userId; // Lia@Note 06-02-26 --- Early return to skip caching for non-existent ID
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
throw new Boom('Invalid id input to find user ids', { statusCode: 400 });
|
|
202
|
+
}
|
|
203
|
+
userId.phoneNumber = jidNormalizedUser(userId.phoneNumber);
|
|
204
|
+
userId.lid = jidNormalizedUser(userId.lid);
|
|
205
|
+
// Lia@Note 06-02-26 --- I know... it's dirty (╯︵╰,)
|
|
206
|
+
USER_ID_CACHE.set(userId.phoneNumber, userId);
|
|
207
|
+
USER_ID_CACHE.set(userId.lid, userId);
|
|
208
|
+
return userId;
|
|
323
209
|
};
|
|
324
210
|
/** update the profile picture for yourself or a group */
|
|
325
|
-
const updateProfilePicture = async (jid, content) => {
|
|
211
|
+
const updateProfilePicture = async (jid, content, dimensions) => {
|
|
326
212
|
let targetJid;
|
|
327
213
|
if (!jid) {
|
|
328
|
-
throw new
|
|
214
|
+
throw new Boom('Illegal no-jid profile update. Please specify either your ID or the ID of the chat you wish to update');
|
|
215
|
+
}
|
|
216
|
+
if (jidNormalizedUser(jid) !== jidNormalizedUser(authState.creds.me.id)) {
|
|
217
|
+
targetJid = jidNormalizedUser(jid); // in case it is someone other than us
|
|
329
218
|
}
|
|
330
|
-
|
|
331
|
-
targetJid =
|
|
219
|
+
else {
|
|
220
|
+
targetJid = undefined;
|
|
332
221
|
}
|
|
333
|
-
const { img } = await (
|
|
222
|
+
const { img } = await generateProfilePicture(content, dimensions);
|
|
334
223
|
await query({
|
|
335
224
|
tag: 'iq',
|
|
336
225
|
attrs: {
|
|
337
|
-
|
|
338
|
-
to: WABinary_1.S_WHATSAPP_NET,
|
|
226
|
+
to: S_WHATSAPP_NET,
|
|
339
227
|
type: 'set',
|
|
340
|
-
xmlns: 'w:profile:picture'
|
|
228
|
+
xmlns: 'w:profile:picture',
|
|
229
|
+
...(targetJid ? { target: targetJid } : {})
|
|
341
230
|
},
|
|
342
231
|
content: [
|
|
343
232
|
{
|
|
@@ -352,18 +241,21 @@ const makeChatsSocket = (config) => {
|
|
|
352
241
|
const removeProfilePicture = async (jid) => {
|
|
353
242
|
let targetJid;
|
|
354
243
|
if (!jid) {
|
|
355
|
-
throw new
|
|
244
|
+
throw new Boom('Illegal no-jid profile update. Please specify either your ID or the ID of the chat you wish to update');
|
|
245
|
+
}
|
|
246
|
+
if (jidNormalizedUser(jid) !== jidNormalizedUser(authState.creds.me.id)) {
|
|
247
|
+
targetJid = jidNormalizedUser(jid); // in case it is someone other than us
|
|
356
248
|
}
|
|
357
|
-
|
|
358
|
-
targetJid =
|
|
249
|
+
else {
|
|
250
|
+
targetJid = undefined;
|
|
359
251
|
}
|
|
360
252
|
await query({
|
|
361
253
|
tag: 'iq',
|
|
362
254
|
attrs: {
|
|
363
|
-
|
|
364
|
-
to: WABinary_1.S_WHATSAPP_NET,
|
|
255
|
+
to: S_WHATSAPP_NET,
|
|
365
256
|
type: 'set',
|
|
366
|
-
xmlns: 'w:profile:picture'
|
|
257
|
+
xmlns: 'w:profile:picture',
|
|
258
|
+
...(targetJid ? { target: targetJid } : {})
|
|
367
259
|
}
|
|
368
260
|
});
|
|
369
261
|
};
|
|
@@ -372,7 +264,7 @@ const makeChatsSocket = (config) => {
|
|
|
372
264
|
await query({
|
|
373
265
|
tag: 'iq',
|
|
374
266
|
attrs: {
|
|
375
|
-
to:
|
|
267
|
+
to: S_WHATSAPP_NET,
|
|
376
268
|
type: 'set',
|
|
377
269
|
xmlns: 'status'
|
|
378
270
|
},
|
|
@@ -393,20 +285,19 @@ const makeChatsSocket = (config) => {
|
|
|
393
285
|
tag: 'iq',
|
|
394
286
|
attrs: {
|
|
395
287
|
xmlns: 'blocklist',
|
|
396
|
-
to:
|
|
288
|
+
to: S_WHATSAPP_NET,
|
|
397
289
|
type: 'get'
|
|
398
290
|
}
|
|
399
291
|
});
|
|
400
|
-
const listNode =
|
|
401
|
-
return
|
|
402
|
-
.map(n => n.attrs.jid);
|
|
292
|
+
const listNode = getBinaryNodeChild(result, 'list');
|
|
293
|
+
return getBinaryNodeChildren(listNode, 'item').map(n => n.attrs.jid);
|
|
403
294
|
};
|
|
404
295
|
const updateBlockStatus = async (jid, action) => {
|
|
405
296
|
await query({
|
|
406
297
|
tag: 'iq',
|
|
407
298
|
attrs: {
|
|
408
299
|
xmlns: 'blocklist',
|
|
409
|
-
to:
|
|
300
|
+
to: S_WHATSAPP_NET,
|
|
410
301
|
type: 'set'
|
|
411
302
|
},
|
|
412
303
|
content: [
|
|
@@ -420,22 +311,70 @@ const makeChatsSocket = (config) => {
|
|
|
420
311
|
]
|
|
421
312
|
});
|
|
422
313
|
};
|
|
314
|
+
const getBusinessProfile = async (jid) => {
|
|
315
|
+
const results = await query({
|
|
316
|
+
tag: 'iq',
|
|
317
|
+
attrs: {
|
|
318
|
+
to: 's.whatsapp.net',
|
|
319
|
+
xmlns: 'w:biz',
|
|
320
|
+
type: 'get'
|
|
321
|
+
},
|
|
322
|
+
content: [
|
|
323
|
+
{
|
|
324
|
+
tag: 'business_profile',
|
|
325
|
+
attrs: { v: '244' },
|
|
326
|
+
content: [
|
|
327
|
+
{
|
|
328
|
+
tag: 'profile',
|
|
329
|
+
attrs: { jid }
|
|
330
|
+
}
|
|
331
|
+
]
|
|
332
|
+
}
|
|
333
|
+
]
|
|
334
|
+
});
|
|
335
|
+
const profileNode = getBinaryNodeChild(results, 'business_profile');
|
|
336
|
+
const profiles = getBinaryNodeChild(profileNode, 'profile');
|
|
337
|
+
if (profiles) {
|
|
338
|
+
const address = getBinaryNodeChild(profiles, 'address');
|
|
339
|
+
const description = getBinaryNodeChild(profiles, 'description');
|
|
340
|
+
const website = getBinaryNodeChild(profiles, 'website');
|
|
341
|
+
const email = getBinaryNodeChild(profiles, 'email');
|
|
342
|
+
const category = getBinaryNodeChild(getBinaryNodeChild(profiles, 'categories'), 'category');
|
|
343
|
+
const businessHours = getBinaryNodeChild(profiles, 'business_hours');
|
|
344
|
+
const businessHoursConfig = businessHours
|
|
345
|
+
? getBinaryNodeChildren(businessHours, 'business_hours_config')
|
|
346
|
+
: undefined;
|
|
347
|
+
const websiteStr = website?.content?.toString();
|
|
348
|
+
return {
|
|
349
|
+
wid: profiles.attrs?.jid,
|
|
350
|
+
address: address?.content?.toString(),
|
|
351
|
+
description: description?.content?.toString() || '',
|
|
352
|
+
website: websiteStr ? [websiteStr] : [],
|
|
353
|
+
email: email?.content?.toString(),
|
|
354
|
+
category: category?.content?.toString(),
|
|
355
|
+
business_hours: {
|
|
356
|
+
timezone: businessHours?.attrs?.timezone,
|
|
357
|
+
business_config: businessHoursConfig?.map(({ attrs }) => attrs)
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
};
|
|
423
362
|
const cleanDirtyBits = async (type, fromTimestamp) => {
|
|
424
363
|
logger.info({ fromTimestamp }, 'clean dirty bits ' + type);
|
|
425
364
|
await sendNode({
|
|
426
365
|
tag: 'iq',
|
|
427
366
|
attrs: {
|
|
428
|
-
to:
|
|
367
|
+
to: S_WHATSAPP_NET,
|
|
429
368
|
type: 'set',
|
|
430
369
|
xmlns: 'urn:xmpp:whatsapp:dirty',
|
|
431
|
-
id: generateMessageTag()
|
|
370
|
+
id: generateMessageTag()
|
|
432
371
|
},
|
|
433
372
|
content: [
|
|
434
373
|
{
|
|
435
374
|
tag: 'clean',
|
|
436
375
|
attrs: {
|
|
437
376
|
type,
|
|
438
|
-
...(fromTimestamp ? { timestamp: fromTimestamp.toString() } : null)
|
|
377
|
+
...(fromTimestamp ? { timestamp: fromTimestamp.toString() } : null)
|
|
439
378
|
}
|
|
440
379
|
}
|
|
441
380
|
]
|
|
@@ -444,26 +383,25 @@ const makeChatsSocket = (config) => {
|
|
|
444
383
|
const newAppStateChunkHandler = (isInitialSync) => {
|
|
445
384
|
return {
|
|
446
385
|
onMutation(mutation) {
|
|
447
|
-
|
|
386
|
+
processSyncAction(mutation, ev, authState.creds.me, isInitialSync ? { accountSettings: authState.creds.accountSettings } : undefined, logger);
|
|
448
387
|
}
|
|
449
388
|
};
|
|
450
389
|
};
|
|
451
|
-
// Buffered version — used for initial sync only (holds events until sync completes)
|
|
452
390
|
const resyncAppState = ev.createBufferedFunction(async (collections, isInitialSync) => {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
391
|
+
const appStateSyncKeyCache = new Map();
|
|
392
|
+
const getCachedAppStateSyncKey = async (keyId) => {
|
|
393
|
+
if (appStateSyncKeyCache.has(keyId)) {
|
|
394
|
+
return appStateSyncKeyCache.get(keyId) ?? undefined;
|
|
395
|
+
}
|
|
396
|
+
const key = await getAppStateSyncKey(keyId);
|
|
397
|
+
appStateSyncKeyCache.set(keyId, key ?? null);
|
|
398
|
+
return key;
|
|
399
|
+
};
|
|
461
400
|
// we use this to determine which events to fire
|
|
462
401
|
// otherwise when we resync from scratch -- all notifications will fire
|
|
463
402
|
const initialVersionMap = {};
|
|
464
403
|
const globalMutationMap = {};
|
|
465
404
|
await authState.keys.transaction(async () => {
|
|
466
|
-
var _a;
|
|
467
405
|
const collectionsToHandle = new Set(collections);
|
|
468
406
|
// in case something goes wrong -- ensure we don't enter a loop that cannot be exited from
|
|
469
407
|
const attemptsMap = {};
|
|
@@ -482,7 +420,7 @@ const makeChatsSocket = (config) => {
|
|
|
482
420
|
}
|
|
483
421
|
}
|
|
484
422
|
else {
|
|
485
|
-
state =
|
|
423
|
+
state = newLTHashState();
|
|
486
424
|
}
|
|
487
425
|
states[name] = state;
|
|
488
426
|
logger.info(`resyncing ${name} from v${state.version}`);
|
|
@@ -492,14 +430,14 @@ const makeChatsSocket = (config) => {
|
|
|
492
430
|
name,
|
|
493
431
|
version: state.version.toString(),
|
|
494
432
|
// return snapshot if being synced from scratch
|
|
495
|
-
|
|
433
|
+
return_snapshot: (!state.version).toString()
|
|
496
434
|
}
|
|
497
435
|
});
|
|
498
436
|
}
|
|
499
437
|
const result = await query({
|
|
500
438
|
tag: 'iq',
|
|
501
439
|
attrs: {
|
|
502
|
-
to:
|
|
440
|
+
to: S_WHATSAPP_NET,
|
|
503
441
|
xmlns: 'w:sync:app:state',
|
|
504
442
|
type: 'set'
|
|
505
443
|
},
|
|
@@ -512,26 +450,22 @@ const makeChatsSocket = (config) => {
|
|
|
512
450
|
]
|
|
513
451
|
});
|
|
514
452
|
// extract from binary node
|
|
515
|
-
const decoded = await
|
|
453
|
+
const decoded = await extractSyncdPatches(result, config?.options);
|
|
516
454
|
for (const key in decoded) {
|
|
517
455
|
const name = key;
|
|
518
456
|
const { patches, hasMorePatches, snapshot } = decoded[name];
|
|
519
457
|
try {
|
|
520
458
|
if (snapshot) {
|
|
521
|
-
const { state: newState, mutationMap } = await
|
|
459
|
+
const { state: newState, mutationMap } = await decodeSyncdSnapshot(name, snapshot, getCachedAppStateSyncKey, initialVersionMap[name], appStateMacVerification.snapshot);
|
|
522
460
|
states[name] = newState;
|
|
523
461
|
Object.assign(globalMutationMap, mutationMap);
|
|
524
462
|
logger.info(`restored state of ${name} from snapshot to v${newState.version} with mutations`);
|
|
525
|
-
await authState.keys.set({ 'app-state-sync-version': {
|
|
526
|
-
[name]: newState
|
|
527
|
-
} });
|
|
463
|
+
await authState.keys.set({ 'app-state-sync-version': { [name]: newState } });
|
|
528
464
|
}
|
|
529
465
|
// only process if there are syncd patches
|
|
530
466
|
if (patches.length) {
|
|
531
|
-
const { state: newState, mutationMap } = await
|
|
532
|
-
await authState.keys.set({ 'app-state-sync-version': {
|
|
533
|
-
[name]: newState
|
|
534
|
-
} });
|
|
467
|
+
const { state: newState, mutationMap } = await decodePatches(name, patches, states[name], getCachedAppStateSyncKey, config.options, initialVersionMap[name], logger, appStateMacVerification.patch);
|
|
468
|
+
await authState.keys.set({ 'app-state-sync-version': { [name]: newState } });
|
|
535
469
|
logger.info(`synced ${name} to v${newState.version}`);
|
|
536
470
|
initialVersionMap[name] = newState.version;
|
|
537
471
|
Object.assign(globalMutationMap, mutationMap);
|
|
@@ -539,7 +473,8 @@ const makeChatsSocket = (config) => {
|
|
|
539
473
|
if (hasMorePatches) {
|
|
540
474
|
logger.info(`${name} has more patches...`);
|
|
541
475
|
}
|
|
542
|
-
else {
|
|
476
|
+
else {
|
|
477
|
+
// collection is done with sync
|
|
543
478
|
collectionsToHandle.delete(name);
|
|
544
479
|
}
|
|
545
480
|
}
|
|
@@ -547,12 +482,10 @@ const makeChatsSocket = (config) => {
|
|
|
547
482
|
// if retry attempts overshoot
|
|
548
483
|
// or key not found
|
|
549
484
|
const isIrrecoverableError = attemptsMap[name] >= MAX_SYNC_ATTEMPTS ||
|
|
550
|
-
|
|
485
|
+
error.output?.statusCode === 404 ||
|
|
551
486
|
error.name === 'TypeError';
|
|
552
487
|
logger.info({ name, error: error.stack }, `failed to sync state from version${isIrrecoverableError ? '' : ', removing and trying from scratch'}`);
|
|
553
|
-
await authState.keys.set({ 'app-state-sync-version': {
|
|
554
|
-
[name]: null
|
|
555
|
-
} });
|
|
488
|
+
await authState.keys.set({ 'app-state-sync-version': { [name]: null } });
|
|
556
489
|
// increment number of retries
|
|
557
490
|
attemptsMap[name] = (attemptsMap[name] || 0) + 1;
|
|
558
491
|
if (isIrrecoverableError) {
|
|
@@ -562,59 +495,102 @@ const makeChatsSocket = (config) => {
|
|
|
562
495
|
}
|
|
563
496
|
}
|
|
564
497
|
}
|
|
565
|
-
});
|
|
498
|
+
}, authState?.creds?.me?.id || 'resync-app-state');
|
|
566
499
|
const { onMutation } = newAppStateChunkHandler(isInitialSync);
|
|
567
500
|
for (const key in globalMutationMap) {
|
|
568
501
|
onMutation(globalMutationMap[key]);
|
|
569
502
|
}
|
|
570
|
-
}
|
|
503
|
+
});
|
|
571
504
|
/**
|
|
572
505
|
* fetch the profile picture of a user/group
|
|
573
506
|
* type = "preview" for a low res picture
|
|
574
507
|
* type = "image for the high res picture"
|
|
575
508
|
*/
|
|
576
|
-
const profilePictureUrl = async (jid, type = '
|
|
577
|
-
|
|
578
|
-
jid =
|
|
509
|
+
const profilePictureUrl = async (jid, type = 'image', timeoutMs) => {
|
|
510
|
+
// vltcs@changes 06-02-26 --- Refactor profilePictureUrl() to use tctoken and adjust error handling
|
|
511
|
+
jid = jidNormalizedUser(jid);
|
|
512
|
+
const baseContent = {
|
|
513
|
+
tag: 'picture',
|
|
514
|
+
attrs: {
|
|
515
|
+
type,
|
|
516
|
+
query: 'url'
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
const tcTokenData = await authState.keys.get('tctoken', [jid]);
|
|
520
|
+
const tcTokenBuffer = tcTokenData?.[jid]?.token
|
|
521
|
+
if (tcTokenBuffer) {
|
|
522
|
+
baseContent.content = [{
|
|
523
|
+
tag: 'tctoken',
|
|
524
|
+
attrs: {},
|
|
525
|
+
content: tcTokenBuffer
|
|
526
|
+
}];
|
|
527
|
+
}
|
|
579
528
|
const result = await query({
|
|
580
529
|
tag: 'iq',
|
|
581
530
|
attrs: {
|
|
582
531
|
target: jid,
|
|
583
|
-
to:
|
|
532
|
+
to: S_WHATSAPP_NET,
|
|
584
533
|
type: 'get',
|
|
585
534
|
xmlns: 'w:profile:picture'
|
|
586
535
|
},
|
|
536
|
+
content: [baseContent]
|
|
537
|
+
}, timeoutMs);
|
|
538
|
+
const child = getBinaryNodeChild(result, 'picture');
|
|
539
|
+
if (!child) {
|
|
540
|
+
throw new Boom('Picture node missing', { statusCode: 404 });
|
|
541
|
+
}
|
|
542
|
+
const status = child.attrs?.status;
|
|
543
|
+
if (status === '404' || status === '204') {
|
|
544
|
+
throw new Boom('Profile picture not set', { statusCode: 404 });
|
|
545
|
+
}
|
|
546
|
+
return child?.attrs?.url;
|
|
547
|
+
};
|
|
548
|
+
const createCallLink = async (type, event, timeoutMs) => {
|
|
549
|
+
const result = await query({
|
|
550
|
+
tag: 'call',
|
|
551
|
+
attrs: {
|
|
552
|
+
id: generateMessageTag(),
|
|
553
|
+
to: '@call'
|
|
554
|
+
},
|
|
587
555
|
content: [
|
|
588
|
-
{
|
|
556
|
+
{
|
|
557
|
+
tag: 'link_create',
|
|
558
|
+
attrs: { media: type },
|
|
559
|
+
content: event ? [{ tag: 'event', attrs: { start_time: String(event.startTime) } }] : undefined
|
|
560
|
+
}
|
|
589
561
|
]
|
|
590
562
|
}, timeoutMs);
|
|
591
|
-
const child =
|
|
592
|
-
return
|
|
563
|
+
const child = getBinaryNodeChild(result, 'link_create');
|
|
564
|
+
return child?.attrs?.token;
|
|
593
565
|
};
|
|
594
566
|
const sendPresenceUpdate = async (type, toJid) => {
|
|
595
567
|
const me = authState.creds.me;
|
|
596
|
-
|
|
568
|
+
const isAvailableType = type === 'available';
|
|
569
|
+
if (isAvailableType || type === 'unavailable') {
|
|
597
570
|
if (!me.name) {
|
|
598
571
|
logger.warn('no name present, ignoring presence update request...');
|
|
599
572
|
return;
|
|
600
573
|
}
|
|
601
|
-
ev.emit('connection.update', { isOnline:
|
|
574
|
+
ev.emit('connection.update', { isOnline: isAvailableType });
|
|
575
|
+
if (isAvailableType) {
|
|
576
|
+
void sendUnifiedSession();
|
|
577
|
+
}
|
|
602
578
|
await sendNode({
|
|
603
579
|
tag: 'presence',
|
|
604
580
|
attrs: {
|
|
605
|
-
name: me.name,
|
|
581
|
+
name: me.name.replace(/@/g, ''),
|
|
606
582
|
type
|
|
607
583
|
}
|
|
608
584
|
});
|
|
609
585
|
}
|
|
610
586
|
else {
|
|
611
|
-
const { server } =
|
|
587
|
+
const { server } = jidDecode(toJid);
|
|
612
588
|
const isLid = server === 'lid';
|
|
613
589
|
await sendNode({
|
|
614
590
|
tag: 'chatstate',
|
|
615
591
|
attrs: {
|
|
616
592
|
from: isLid ? me.lid : me.id,
|
|
617
|
-
to: toJid
|
|
593
|
+
to: toJid
|
|
618
594
|
},
|
|
619
595
|
content: [
|
|
620
596
|
{
|
|
@@ -629,29 +605,23 @@ const makeChatsSocket = (config) => {
|
|
|
629
605
|
* @param toJid the jid to subscribe to
|
|
630
606
|
* @param tcToken token for subscription, use if present
|
|
631
607
|
*/
|
|
632
|
-
const presenceSubscribe = (toJid
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
content: tcToken
|
|
645
|
-
}
|
|
646
|
-
] :
|
|
647
|
-
undefined
|
|
648
|
-
}));
|
|
608
|
+
const presenceSubscribe = async (toJid) => {
|
|
609
|
+
const tcTokenContent = await buildTcTokenFromJid({ authState, jid: toJid });
|
|
610
|
+
return sendNode({
|
|
611
|
+
tag: 'presence',
|
|
612
|
+
attrs: {
|
|
613
|
+
to: toJid,
|
|
614
|
+
id: generateMessageTag(),
|
|
615
|
+
type: 'subscribe'
|
|
616
|
+
},
|
|
617
|
+
content: tcTokenContent
|
|
618
|
+
});
|
|
619
|
+
};
|
|
649
620
|
const handlePresenceUpdate = ({ tag, attrs, content }) => {
|
|
650
|
-
var _a;
|
|
651
621
|
let presence;
|
|
652
622
|
const jid = attrs.from;
|
|
653
623
|
const participant = attrs.participant || attrs.from;
|
|
654
|
-
if (shouldIgnoreJid(jid) && jid !==
|
|
624
|
+
if (shouldIgnoreJid(jid) && jid !== S_WHATSAPP_NET) {
|
|
655
625
|
return;
|
|
656
626
|
}
|
|
657
627
|
if (tag === 'presence') {
|
|
@@ -666,7 +636,7 @@ const makeChatsSocket = (config) => {
|
|
|
666
636
|
if (type === 'paused') {
|
|
667
637
|
type = 'available';
|
|
668
638
|
}
|
|
669
|
-
if (
|
|
639
|
+
if (firstChild.attrs?.media === 'audio') {
|
|
670
640
|
type = 'recording';
|
|
671
641
|
}
|
|
672
642
|
presence = { lastKnownPresence: type };
|
|
@@ -675,31 +645,29 @@ const makeChatsSocket = (config) => {
|
|
|
675
645
|
logger.error({ tag, attrs, content }, 'recv invalid presence node');
|
|
676
646
|
}
|
|
677
647
|
if (presence) {
|
|
678
|
-
ev.emit('presence.update', { id: jid, presences: {
|
|
679
|
-
[participant]: presence
|
|
680
|
-
} });
|
|
648
|
+
ev.emit('presence.update', { id: jid, presences: { [participant]: presence } });
|
|
681
649
|
}
|
|
682
650
|
};
|
|
683
651
|
const appPatch = async (patchCreate) => {
|
|
684
652
|
const name = patchCreate.type;
|
|
685
653
|
const myAppStateKeyId = authState.creds.myAppStateKeyId;
|
|
686
654
|
if (!myAppStateKeyId) {
|
|
687
|
-
throw new
|
|
655
|
+
throw new Boom('App state key not present!', { statusCode: 400 });
|
|
688
656
|
}
|
|
689
657
|
let initial;
|
|
690
658
|
let encodeResult;
|
|
691
|
-
await
|
|
659
|
+
await appStatePatchMutex.mutex(async () => {
|
|
692
660
|
await authState.keys.transaction(async () => {
|
|
693
661
|
logger.debug({ patch: patchCreate }, 'applying app patch');
|
|
694
662
|
await resyncAppState([name], false);
|
|
695
663
|
const { [name]: currentSyncVersion } = await authState.keys.get('app-state-sync-version', [name]);
|
|
696
|
-
initial = currentSyncVersion ||
|
|
697
|
-
encodeResult = await
|
|
664
|
+
initial = currentSyncVersion || newLTHashState();
|
|
665
|
+
encodeResult = await encodeSyncdPatch(patchCreate, myAppStateKeyId, initial, getAppStateSyncKey);
|
|
698
666
|
const { patch, state } = encodeResult;
|
|
699
667
|
const node = {
|
|
700
668
|
tag: 'iq',
|
|
701
669
|
attrs: {
|
|
702
|
-
to:
|
|
670
|
+
to: S_WHATSAPP_NET,
|
|
703
671
|
type: 'set',
|
|
704
672
|
xmlns: 'w:sync:app:state'
|
|
705
673
|
},
|
|
@@ -713,13 +681,13 @@ const makeChatsSocket = (config) => {
|
|
|
713
681
|
attrs: {
|
|
714
682
|
name,
|
|
715
683
|
version: (state.version - 1).toString(),
|
|
716
|
-
|
|
684
|
+
return_snapshot: 'false'
|
|
717
685
|
},
|
|
718
686
|
content: [
|
|
719
687
|
{
|
|
720
688
|
tag: 'patch',
|
|
721
689
|
attrs: {},
|
|
722
|
-
content:
|
|
690
|
+
content: proto.SyncdPatch.encode(patch).finish()
|
|
723
691
|
}
|
|
724
692
|
]
|
|
725
693
|
}
|
|
@@ -728,14 +696,12 @@ const makeChatsSocket = (config) => {
|
|
|
728
696
|
]
|
|
729
697
|
};
|
|
730
698
|
await query(node);
|
|
731
|
-
await authState.keys.set({ 'app-state-sync-version': {
|
|
732
|
-
|
|
733
|
-
} });
|
|
734
|
-
});
|
|
699
|
+
await authState.keys.set({ 'app-state-sync-version': { [name]: state } });
|
|
700
|
+
}, authState?.creds?.me?.id || 'app-patch');
|
|
735
701
|
});
|
|
736
702
|
if (config.emitOwnEvents) {
|
|
737
703
|
const { onMutation } = newAppStateChunkHandler(false);
|
|
738
|
-
const { mutationMap } = await
|
|
704
|
+
const { mutationMap } = await decodePatches(name, [{ ...encodeResult.patch, version: { version: encodeResult.state.version } }], initial, getAppStateSyncKey, config.options, undefined, logger);
|
|
739
705
|
for (const key in mutationMap) {
|
|
740
706
|
onMutation(mutationMap[key]);
|
|
741
707
|
}
|
|
@@ -743,30 +709,33 @@ const makeChatsSocket = (config) => {
|
|
|
743
709
|
};
|
|
744
710
|
/** sending non-abt props may fix QR scan fail if server expects */
|
|
745
711
|
const fetchProps = async () => {
|
|
746
|
-
|
|
712
|
+
//TODO: implement both protocol 1 and protocol 2 prop fetching, specially for abKey for WM
|
|
747
713
|
const resultNode = await query({
|
|
748
714
|
tag: 'iq',
|
|
749
715
|
attrs: {
|
|
750
|
-
to:
|
|
716
|
+
to: S_WHATSAPP_NET,
|
|
751
717
|
xmlns: 'w',
|
|
752
|
-
type: 'get'
|
|
718
|
+
type: 'get'
|
|
753
719
|
},
|
|
754
720
|
content: [
|
|
755
721
|
{
|
|
756
722
|
tag: 'props',
|
|
757
723
|
attrs: {
|
|
758
724
|
protocol: '2',
|
|
759
|
-
hash:
|
|
725
|
+
hash: authState?.creds?.lastPropHash || ''
|
|
760
726
|
}
|
|
761
727
|
}
|
|
762
728
|
]
|
|
763
729
|
});
|
|
764
|
-
const propsNode =
|
|
730
|
+
const propsNode = getBinaryNodeChild(resultNode, 'props');
|
|
765
731
|
let props = {};
|
|
766
732
|
if (propsNode) {
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
733
|
+
if (propsNode.attrs?.hash) {
|
|
734
|
+
// on some clients, the hash is returning as undefined
|
|
735
|
+
authState.creds.lastPropHash = propsNode?.attrs?.hash;
|
|
736
|
+
ev.emit('creds.update', authState.creds);
|
|
737
|
+
}
|
|
738
|
+
props = reduceBinaryNodeToDictionary(propsNode, 'prop');
|
|
770
739
|
}
|
|
771
740
|
logger.debug('fetched props');
|
|
772
741
|
return props;
|
|
@@ -777,9 +746,17 @@ const makeChatsSocket = (config) => {
|
|
|
777
746
|
* requires the last messages till the last message received; required for archive & unread
|
|
778
747
|
*/
|
|
779
748
|
const chatModify = (mod, jid) => {
|
|
780
|
-
const patch =
|
|
749
|
+
const patch = chatModificationToAppPatch(mod, jid);
|
|
781
750
|
return appPatch(patch);
|
|
782
751
|
};
|
|
752
|
+
/**
|
|
753
|
+
* Enable/Disable link preview privacy, not related to baileys link preview generation
|
|
754
|
+
*/
|
|
755
|
+
const updateDisableLinkPreviewsPrivacy = (isPreviewsDisabled) => {
|
|
756
|
+
return chatModify({
|
|
757
|
+
disableLinkPreviews: { isPreviewsDisabled }
|
|
758
|
+
}, '');
|
|
759
|
+
};
|
|
783
760
|
/**
|
|
784
761
|
* Star or Unstar a message
|
|
785
762
|
*/
|
|
@@ -791,6 +768,32 @@ const makeChatsSocket = (config) => {
|
|
|
791
768
|
}
|
|
792
769
|
}, jid);
|
|
793
770
|
};
|
|
771
|
+
/**
|
|
772
|
+
* Add or Edit Contact
|
|
773
|
+
*/
|
|
774
|
+
const addOrEditContact = (jid, contact) => {
|
|
775
|
+
return chatModify({
|
|
776
|
+
contact
|
|
777
|
+
}, jid);
|
|
778
|
+
};
|
|
779
|
+
/**
|
|
780
|
+
* Remove Contact
|
|
781
|
+
*/
|
|
782
|
+
const removeContact = (jid) => {
|
|
783
|
+
return chatModify({
|
|
784
|
+
contact: null
|
|
785
|
+
}, jid);
|
|
786
|
+
};
|
|
787
|
+
/**
|
|
788
|
+
* Adds label
|
|
789
|
+
*/
|
|
790
|
+
const addLabel = (jid, labels) => {
|
|
791
|
+
return chatModify({
|
|
792
|
+
addLabel: {
|
|
793
|
+
...labels
|
|
794
|
+
}
|
|
795
|
+
}, jid);
|
|
796
|
+
};
|
|
794
797
|
/**
|
|
795
798
|
* Adds label for the chats
|
|
796
799
|
*/
|
|
@@ -833,82 +836,104 @@ const makeChatsSocket = (config) => {
|
|
|
833
836
|
}
|
|
834
837
|
}, jid);
|
|
835
838
|
};
|
|
839
|
+
/**
|
|
840
|
+
* Add or Edit Quick Reply
|
|
841
|
+
*/
|
|
842
|
+
const addOrEditQuickReply = (quickReply) => {
|
|
843
|
+
return chatModify({
|
|
844
|
+
quickReply
|
|
845
|
+
}, '');
|
|
846
|
+
};
|
|
847
|
+
/**
|
|
848
|
+
* Remove Quick Reply
|
|
849
|
+
*/
|
|
850
|
+
const removeQuickReply = (timestamp) => {
|
|
851
|
+
return chatModify({
|
|
852
|
+
quickReply: { timestamp, deleted: true }
|
|
853
|
+
}, '');
|
|
854
|
+
};
|
|
836
855
|
/**
|
|
837
856
|
* queries need to be fired on connection open
|
|
838
857
|
* help ensure parity with WA Web
|
|
839
858
|
* */
|
|
840
859
|
const executeInitQueries = async () => {
|
|
841
|
-
await Promise.all([
|
|
842
|
-
fetchProps(),
|
|
843
|
-
fetchBlocklist(),
|
|
844
|
-
fetchPrivacySettings(),
|
|
845
|
-
]);
|
|
860
|
+
await Promise.all([fetchProps(), fetchBlocklist(), fetchPrivacySettings()]);
|
|
846
861
|
};
|
|
847
862
|
const upsertMessage = ev.createBufferedFunction(async (msg, type) => {
|
|
848
|
-
var _a, _b, _c;
|
|
849
863
|
ev.emit('messages.upsert', { messages: [msg], type });
|
|
850
864
|
if (!!msg.pushName) {
|
|
851
|
-
let jid = msg.key.fromMe ? authState.creds.me.id :
|
|
852
|
-
jid =
|
|
865
|
+
let jid = msg.key.fromMe ? authState.creds.me.id : msg.key.participant || msg.key.remoteJid;
|
|
866
|
+
jid = jidNormalizedUser(jid);
|
|
853
867
|
if (!msg.key.fromMe) {
|
|
854
868
|
ev.emit('contacts.update', [{ id: jid, notify: msg.pushName, verifiedName: msg.verifiedBizName }]);
|
|
855
869
|
}
|
|
856
870
|
// update our pushname too
|
|
857
|
-
if (msg.key.fromMe && msg.pushName &&
|
|
871
|
+
if (msg.key.fromMe && msg.pushName && authState.creds.me?.name !== msg.pushName) {
|
|
858
872
|
ev.emit('creds.update', { me: { ...authState.creds.me, name: msg.pushName } });
|
|
859
873
|
}
|
|
860
874
|
}
|
|
861
|
-
const historyMsg =
|
|
862
|
-
const shouldProcessHistoryMsg = historyMsg
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
false;
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
// are not delayed while the potentially large state sync runs on reconnect
|
|
872
|
-
const appStateSyncPromise = (async () => {
|
|
873
|
-
if (historyMsg && authState.creds.myAppStateKeyId) {
|
|
874
|
-
pendingAppStateSync = false;
|
|
875
|
-
await doAppStateSync();
|
|
875
|
+
const historyMsg = getHistoryMsg(msg.message);
|
|
876
|
+
const shouldProcessHistoryMsg = historyMsg
|
|
877
|
+
? shouldSyncHistoryMessage(historyMsg) &&
|
|
878
|
+
PROCESSABLE_HISTORY_TYPES.includes(historyMsg.syncType)
|
|
879
|
+
: false;
|
|
880
|
+
// State machine: decide on sync and flush
|
|
881
|
+
if (historyMsg && syncState === SyncState.AwaitingInitialSync) {
|
|
882
|
+
if (awaitingSyncTimeout) {
|
|
883
|
+
clearTimeout(awaitingSyncTimeout);
|
|
884
|
+
awaitingSyncTimeout = undefined;
|
|
876
885
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
if (!authState.creds.accountSyncCounter) {
|
|
897
|
-
logger.info('doing initial app state sync');
|
|
898
|
-
await resyncAppState(Types_1.ALL_WA_PATCH_NAMES, true);
|
|
886
|
+
if (shouldProcessHistoryMsg) {
|
|
887
|
+
syncState = SyncState.Syncing;
|
|
888
|
+
logger.info('Transitioned to Syncing state');
|
|
889
|
+
// Let doAppStateSync handle the final flush after it's done
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
syncState = SyncState.Online;
|
|
893
|
+
logger.info('History sync skipped, transitioning to Online state and flushing buffer');
|
|
894
|
+
ev.flush();
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
const doAppStateSync = async () => {
|
|
898
|
+
if (syncState === SyncState.Syncing) {
|
|
899
|
+
logger.info('Doing app state sync');
|
|
900
|
+
await resyncAppState(ALL_WA_PATCH_NAMES, true);
|
|
901
|
+
// Sync is complete, go online and flush everything
|
|
902
|
+
syncState = SyncState.Online;
|
|
903
|
+
logger.info('App state sync complete, transitioning to Online state and flushing buffer');
|
|
904
|
+
ev.flush();
|
|
899
905
|
const accountSyncCounter = (authState.creds.accountSyncCounter || 0) + 1;
|
|
900
906
|
ev.emit('creds.update', { accountSyncCounter });
|
|
901
|
-
if (needToFlushWithAppStateSync) {
|
|
902
|
-
logger.debug('flushing with app state sync');
|
|
903
|
-
ev.flush();
|
|
904
|
-
}
|
|
905
907
|
}
|
|
908
|
+
};
|
|
909
|
+
await Promise.all([
|
|
910
|
+
(async () => {
|
|
911
|
+
if (shouldProcessHistoryMsg) {
|
|
912
|
+
await doAppStateSync();
|
|
913
|
+
}
|
|
914
|
+
})(),
|
|
915
|
+
processMessage(msg, {
|
|
916
|
+
signalRepository,
|
|
917
|
+
shouldProcessHistoryMsg,
|
|
918
|
+
placeholderResendCache,
|
|
919
|
+
ev,
|
|
920
|
+
creds: authState.creds,
|
|
921
|
+
keyStore: authState.keys,
|
|
922
|
+
logger,
|
|
923
|
+
options: config.options,
|
|
924
|
+
getMessage
|
|
925
|
+
})
|
|
926
|
+
]);
|
|
927
|
+
// If the app state key arrives and we are waiting to sync, trigger the sync now.
|
|
928
|
+
if (msg.message?.protocolMessage?.appStateSyncKeyShare && syncState === SyncState.Syncing) {
|
|
929
|
+
logger.info('App state sync key arrived, triggering app state sync');
|
|
930
|
+
await doAppStateSync();
|
|
906
931
|
}
|
|
907
932
|
});
|
|
908
933
|
ws.on('CB:presence', handlePresenceUpdate);
|
|
909
934
|
ws.on('CB:chatstate', handlePresenceUpdate);
|
|
910
935
|
ws.on('CB:ib,,dirty', async (node) => {
|
|
911
|
-
const { attrs } =
|
|
936
|
+
const { attrs } = getBinaryNodeChild(node, 'dirty');
|
|
912
937
|
const type = attrs.type;
|
|
913
938
|
switch (type) {
|
|
914
939
|
case 'account_sync':
|
|
@@ -930,42 +955,74 @@ const makeChatsSocket = (config) => {
|
|
|
930
955
|
}
|
|
931
956
|
});
|
|
932
957
|
ev.on('connection.update', ({ connection, receivedPendingNotifications }) => {
|
|
933
|
-
var _a;
|
|
934
958
|
if (connection === 'open') {
|
|
935
959
|
if (fireInitQueries) {
|
|
936
|
-
executeInitQueries()
|
|
937
|
-
.catch(error => onUnexpectedError(error, 'init queries'));
|
|
960
|
+
executeInitQueries().catch(error => onUnexpectedError(error, 'init queries'));
|
|
938
961
|
}
|
|
939
|
-
sendPresenceUpdate(markOnlineOnConnect ? 'available' : 'unavailable')
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
962
|
+
sendPresenceUpdate(markOnlineOnConnect ? 'available' : 'unavailable').catch(error => onUnexpectedError(error, 'presence update requests'));
|
|
963
|
+
}
|
|
964
|
+
if (!receivedPendingNotifications || syncState !== SyncState.Connecting) {
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
syncState = SyncState.AwaitingInitialSync;
|
|
968
|
+
logger.info('Connection is now AwaitingInitialSync, buffering events');
|
|
969
|
+
ev.buffer();
|
|
970
|
+
const willSyncHistory = shouldSyncHistoryMessage(proto.Message.HistorySyncNotification.create({
|
|
971
|
+
syncType: proto.HistorySync.HistorySyncType.RECENT
|
|
972
|
+
}));
|
|
973
|
+
if (!willSyncHistory) {
|
|
974
|
+
logger.info('History sync is disabled by config, not waiting for notification. Transitioning to Online.');
|
|
975
|
+
syncState = SyncState.Online;
|
|
976
|
+
setTimeout(() => ev.flush(), 0);
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
logger.info('History sync is enabled, awaiting notification with a 20s timeout.');
|
|
980
|
+
if (awaitingSyncTimeout) {
|
|
981
|
+
clearTimeout(awaitingSyncTimeout);
|
|
982
|
+
}
|
|
983
|
+
awaitingSyncTimeout = setTimeout(() => {
|
|
984
|
+
if (syncState === SyncState.AwaitingInitialSync) {
|
|
985
|
+
// TODO: investigate
|
|
986
|
+
logger.warn('Timeout in AwaitingInitialSync, forcing state to Online and flushing buffer');
|
|
987
|
+
syncState = SyncState.Online;
|
|
988
|
+
ev.flush();
|
|
949
989
|
}
|
|
990
|
+
}, 20000);
|
|
991
|
+
});
|
|
992
|
+
ev.on('lid-mapping.update', async ({ lid, pn }) => {
|
|
993
|
+
try {
|
|
994
|
+
await signalRepository.lidMapping.storeLIDPNMappings([{ lid, pn }]);
|
|
995
|
+
}
|
|
996
|
+
catch (error) {
|
|
997
|
+
logger.warn({ lid, pn, error }, 'Failed to store LID-PN mapping');
|
|
950
998
|
}
|
|
951
999
|
});
|
|
952
1000
|
return {
|
|
953
1001
|
...sock,
|
|
954
|
-
|
|
1002
|
+
createCallLink,
|
|
1003
|
+
getBotListV2,
|
|
1004
|
+
messageMutex,
|
|
1005
|
+
receiptMutex,
|
|
1006
|
+
appStatePatchMutex,
|
|
1007
|
+
notificationMutex,
|
|
955
1008
|
fetchPrivacySettings,
|
|
956
1009
|
upsertMessage,
|
|
957
1010
|
appPatch,
|
|
958
1011
|
sendPresenceUpdate,
|
|
959
1012
|
presenceSubscribe,
|
|
960
1013
|
profilePictureUrl,
|
|
961
|
-
onWhatsApp,
|
|
962
1014
|
fetchBlocklist,
|
|
963
1015
|
fetchStatus,
|
|
1016
|
+
fetchDisappearingDuration,
|
|
1017
|
+
findUserId,
|
|
964
1018
|
updateProfilePicture,
|
|
965
1019
|
removeProfilePicture,
|
|
966
1020
|
updateProfileStatus,
|
|
967
1021
|
updateProfileName,
|
|
968
1022
|
updateBlockStatus,
|
|
1023
|
+
updateDisableLinkPreviewsPrivacy,
|
|
1024
|
+
updateCallPrivacy,
|
|
1025
|
+
updateMessagesPrivacy,
|
|
969
1026
|
updateLastSeenPrivacy,
|
|
970
1027
|
updateOnlinePrivacy,
|
|
971
1028
|
updateProfilePicturePrivacy,
|
|
@@ -977,13 +1034,15 @@ const makeChatsSocket = (config) => {
|
|
|
977
1034
|
resyncAppState,
|
|
978
1035
|
chatModify,
|
|
979
1036
|
cleanDirtyBits,
|
|
1037
|
+
addOrEditContact,
|
|
1038
|
+
removeContact,
|
|
1039
|
+
addLabel,
|
|
980
1040
|
addChatLabel,
|
|
981
1041
|
removeChatLabel,
|
|
982
1042
|
addMessageLabel,
|
|
983
|
-
checkWhatsApp,
|
|
984
|
-
reqPairing,
|
|
985
1043
|
removeMessageLabel,
|
|
986
|
-
star
|
|
1044
|
+
star,
|
|
1045
|
+
addOrEditQuickReply,
|
|
1046
|
+
removeQuickReply
|
|
987
1047
|
};
|
|
988
|
-
};
|
|
989
|
-
exports.makeChatsSocket = makeChatsSocket;
|
|
1048
|
+
};
|