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/Utils/chat-utils.js
CHANGED
|
@@ -1,44 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const messages_media_1 = require("./messages-media");
|
|
1
|
+
import { Boom } from '@hapi/boom';
|
|
2
|
+
import { expandAppStateKeys } from 'whatsapp-rust-bridge';
|
|
3
|
+
import { proto } from '../../WAProto/index.js';
|
|
4
|
+
import { LabelAssociationType } from '../Types/LabelAssociation.js';
|
|
5
|
+
import { getBinaryNodeChild, getBinaryNodeChildren, isJidGroup, jidNormalizedUser } from '../WABinary/index.js';
|
|
6
|
+
import { aesDecrypt, aesEncrypt, hmacSign } from './crypto.js';
|
|
7
|
+
import { toNumber } from './generics.js';
|
|
8
|
+
import { LT_HASH_ANTI_TAMPERING } from './lt-hash.js';
|
|
9
|
+
import { downloadContentFromMessage } from './messages-media.js';
|
|
10
|
+
import { emitSyncActionResults, processContactAction } from './sync-action-utils.js';
|
|
12
11
|
const mutationKeys = (keydata) => {
|
|
13
|
-
const
|
|
12
|
+
const keys = expandAppStateKeys(keydata);
|
|
14
13
|
return {
|
|
15
|
-
indexKey:
|
|
16
|
-
valueEncryptionKey:
|
|
17
|
-
valueMacKey:
|
|
18
|
-
snapshotMacKey:
|
|
19
|
-
patchMacKey:
|
|
14
|
+
indexKey: keys.indexKey,
|
|
15
|
+
valueEncryptionKey: keys.valueEncryptionKey,
|
|
16
|
+
valueMacKey: keys.valueMacKey,
|
|
17
|
+
snapshotMacKey: keys.snapshotMacKey,
|
|
18
|
+
patchMacKey: keys.patchMacKey
|
|
20
19
|
};
|
|
21
20
|
};
|
|
22
21
|
const generateMac = (operation, data, keyId, key) => {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const keyData = getKeyData();
|
|
37
|
-
const last = Buffer.alloc(8); // 8 bytes
|
|
38
|
-
last.set([keyData.length], last.length - 1);
|
|
39
|
-
const total = Buffer.concat([keyData, data, last]);
|
|
40
|
-
const hmac = (0, crypto_1.hmacSign)(total, key, 'sha512');
|
|
41
|
-
return hmac.slice(0, 32);
|
|
22
|
+
const opByte = operation === proto.SyncdMutation.SyncdOperation.SET ? 0x01 : 0x02;
|
|
23
|
+
const keyIdBuffer = typeof keyId === 'string' ? Buffer.from(keyId, 'base64') : keyId;
|
|
24
|
+
const keyData = new Uint8Array(1 + keyIdBuffer.length);
|
|
25
|
+
keyData[0] = opByte;
|
|
26
|
+
keyData.set(keyIdBuffer, 1);
|
|
27
|
+
const last = new Uint8Array(8);
|
|
28
|
+
last[7] = keyData.length;
|
|
29
|
+
const total = new Uint8Array(keyData.length + data.length + last.length);
|
|
30
|
+
total.set(keyData, 0);
|
|
31
|
+
total.set(data, keyData.length);
|
|
32
|
+
total.set(last, keyData.length + data.length);
|
|
33
|
+
const hmac = hmacSign(total, key, 'sha512');
|
|
34
|
+
return hmac.subarray(0, 32);
|
|
42
35
|
};
|
|
43
36
|
const to64BitNetworkOrder = (e) => {
|
|
44
37
|
const buff = Buffer.alloc(8);
|
|
@@ -53,71 +46,59 @@ const makeLtHashGenerator = ({ indexValueMap, hash }) => {
|
|
|
53
46
|
mix: ({ indexMac, valueMac, operation }) => {
|
|
54
47
|
const indexMacBase64 = Buffer.from(indexMac).toString('base64');
|
|
55
48
|
const prevOp = indexValueMap[indexMacBase64];
|
|
56
|
-
if (operation ===
|
|
49
|
+
if (operation === proto.SyncdMutation.SyncdOperation.REMOVE) {
|
|
57
50
|
if (!prevOp) {
|
|
58
|
-
throw new
|
|
51
|
+
throw new Boom('tried remove, but no previous op', { data: { indexMac, valueMac } });
|
|
59
52
|
}
|
|
60
53
|
// remove from index value mac, since this mutation is erased
|
|
61
54
|
delete indexValueMap[indexMacBase64];
|
|
62
55
|
}
|
|
63
56
|
else {
|
|
64
|
-
addBuffs.push(
|
|
57
|
+
addBuffs.push(valueMac);
|
|
65
58
|
// add this index into the history map
|
|
66
59
|
indexValueMap[indexMacBase64] = { valueMac };
|
|
67
60
|
}
|
|
68
61
|
if (prevOp) {
|
|
69
|
-
subBuffs.push(
|
|
62
|
+
subBuffs.push(prevOp.valueMac);
|
|
70
63
|
}
|
|
71
64
|
},
|
|
72
65
|
finish: () => {
|
|
73
|
-
const
|
|
74
|
-
const result = lt_hash_1.LT_HASH_ANTI_TAMPERING.subtractThenAdd(hashArrayBuffer, addBuffs, subBuffs);
|
|
75
|
-
const buffer = Buffer.from(result);
|
|
66
|
+
const result = LT_HASH_ANTI_TAMPERING.subtractThenAdd(hash, subBuffs, addBuffs);
|
|
76
67
|
return {
|
|
77
|
-
hash:
|
|
68
|
+
hash: Buffer.from(result),
|
|
78
69
|
indexValueMap
|
|
79
70
|
};
|
|
80
71
|
}
|
|
81
72
|
};
|
|
82
73
|
};
|
|
83
74
|
const generateSnapshotMac = (lthash, version, name, key) => {
|
|
84
|
-
const total = Buffer.concat([
|
|
85
|
-
|
|
86
|
-
to64BitNetworkOrder(version),
|
|
87
|
-
Buffer.from(name, 'utf-8')
|
|
88
|
-
]);
|
|
89
|
-
return (0, crypto_1.hmacSign)(total, key, 'sha256');
|
|
75
|
+
const total = Buffer.concat([lthash, to64BitNetworkOrder(version), Buffer.from(name, 'utf-8')]);
|
|
76
|
+
return hmacSign(total, key, 'sha256');
|
|
90
77
|
};
|
|
91
78
|
const generatePatchMac = (snapshotMac, valueMacs, version, type, key) => {
|
|
92
|
-
const total = Buffer.concat([
|
|
93
|
-
|
|
94
|
-
...valueMacs,
|
|
95
|
-
to64BitNetworkOrder(version),
|
|
96
|
-
Buffer.from(type, 'utf-8')
|
|
97
|
-
]);
|
|
98
|
-
return (0, crypto_1.hmacSign)(total, key);
|
|
79
|
+
const total = Buffer.concat([snapshotMac, ...valueMacs, to64BitNetworkOrder(version), Buffer.from(type, 'utf-8')]);
|
|
80
|
+
return hmacSign(total, key);
|
|
99
81
|
};
|
|
100
|
-
const newLTHashState = () => ({ version: 0, hash: Buffer.alloc(128), indexValueMap: {} });
|
|
101
|
-
|
|
102
|
-
const encodeSyncdPatch = async ({ type, index, syncAction, apiVersion, operation }, myAppStateKeyId, state, getAppStateSyncKey) => {
|
|
82
|
+
export const newLTHashState = () => ({ version: 0, hash: Buffer.alloc(128), indexValueMap: {} });
|
|
83
|
+
export const encodeSyncdPatch = async ({ type, index, syncAction, apiVersion, operation }, myAppStateKeyId, state, getAppStateSyncKey) => {
|
|
103
84
|
const key = !!myAppStateKeyId ? await getAppStateSyncKey(myAppStateKeyId) : undefined;
|
|
104
85
|
if (!key) {
|
|
105
|
-
throw new
|
|
86
|
+
throw new Boom(`myAppStateKey ("${myAppStateKeyId}") not present`, { statusCode: 404 });
|
|
106
87
|
}
|
|
107
88
|
const encKeyId = Buffer.from(myAppStateKeyId, 'base64');
|
|
108
89
|
state = { ...state, indexValueMap: { ...state.indexValueMap } };
|
|
109
90
|
const indexBuffer = Buffer.from(JSON.stringify(index));
|
|
110
|
-
const dataProto =
|
|
91
|
+
const dataProto = proto.SyncActionData.fromObject({
|
|
111
92
|
index: indexBuffer,
|
|
112
93
|
value: syncAction,
|
|
113
94
|
padding: new Uint8Array(0),
|
|
114
95
|
version: apiVersion
|
|
115
96
|
});
|
|
116
|
-
const encoded =
|
|
97
|
+
const encoded = proto.SyncActionData.encode(dataProto).finish();
|
|
117
98
|
const keyValue = mutationKeys(key.keyData);
|
|
118
|
-
const encValue =
|
|
99
|
+
const encValue = aesEncrypt(encoded, keyValue.valueEncryptionKey);
|
|
119
100
|
const valueMac = generateMac(operation, encValue, encKeyId, keyValue.valueMacKey);
|
|
120
|
-
const indexMac =
|
|
101
|
+
const indexMac = hmacSign(indexBuffer, keyValue.indexKey);
|
|
121
102
|
// update LT hash
|
|
122
103
|
const generator = makeLtHashGenerator(state);
|
|
123
104
|
generator.mix({ indexMac, valueMac, operation });
|
|
@@ -147,33 +128,33 @@ const encodeSyncdPatch = async ({ type, index, syncAction, apiVersion, operation
|
|
|
147
128
|
state.indexValueMap[base64Index] = { valueMac };
|
|
148
129
|
return { patch, state };
|
|
149
130
|
};
|
|
150
|
-
|
|
151
|
-
const decodeSyncdMutations = async (msgMutations, initialState, getAppStateSyncKey, onMutation, validateMacs) => {
|
|
131
|
+
export const decodeSyncdMutations = async (msgMutations, initialState, getAppStateSyncKey, onMutation, validateMacs) => {
|
|
152
132
|
const ltGenerator = makeLtHashGenerator(initialState);
|
|
133
|
+
const derivedKeyCache = new Map();
|
|
153
134
|
// indexKey used to HMAC sign record.index.blob
|
|
154
135
|
// valueEncryptionKey used to AES-256-CBC encrypt record.value.blob[0:-32]
|
|
155
136
|
// the remaining record.value.blob[0:-32] is the mac, it the HMAC sign of key.keyId + decoded proto data + length of bytes in keyId
|
|
156
137
|
for (const msgMutation of msgMutations) {
|
|
157
138
|
// if it's a syncdmutation, get the operation property
|
|
158
139
|
// otherwise, if it's only a record -- it'll be a SET mutation
|
|
159
|
-
const operation = 'operation' in msgMutation ? msgMutation.operation :
|
|
160
|
-
const record =
|
|
140
|
+
const operation = 'operation' in msgMutation ? msgMutation.operation : proto.SyncdMutation.SyncdOperation.SET;
|
|
141
|
+
const record = 'record' in msgMutation && !!msgMutation.record ? msgMutation.record : msgMutation;
|
|
161
142
|
const key = await getKey(record.keyId.id);
|
|
162
|
-
const content =
|
|
163
|
-
const encContent = content.
|
|
164
|
-
const ogValueMac = content.
|
|
143
|
+
const content = record.value.blob;
|
|
144
|
+
const encContent = content.subarray(0, -32);
|
|
145
|
+
const ogValueMac = content.subarray(-32);
|
|
165
146
|
if (validateMacs) {
|
|
166
147
|
const contentHmac = generateMac(operation, encContent, record.keyId.id, key.valueMacKey);
|
|
167
148
|
if (Buffer.compare(contentHmac, ogValueMac) !== 0) {
|
|
168
|
-
throw new
|
|
149
|
+
throw new Boom('HMAC content verification failed');
|
|
169
150
|
}
|
|
170
151
|
}
|
|
171
|
-
const result =
|
|
172
|
-
const syncAction =
|
|
152
|
+
const result = aesDecrypt(encContent, key.valueEncryptionKey);
|
|
153
|
+
const syncAction = proto.SyncActionData.decode(result);
|
|
173
154
|
if (validateMacs) {
|
|
174
|
-
const hmac =
|
|
155
|
+
const hmac = hmacSign(syncAction.index, key.indexKey);
|
|
175
156
|
if (Buffer.compare(hmac, record.index.blob) !== 0) {
|
|
176
|
-
throw new
|
|
157
|
+
throw new Boom('HMAC index verification failed');
|
|
177
158
|
}
|
|
178
159
|
}
|
|
179
160
|
const indexStr = Buffer.from(syncAction.index).toString();
|
|
@@ -187,40 +168,47 @@ const decodeSyncdMutations = async (msgMutations, initialState, getAppStateSyncK
|
|
|
187
168
|
return ltGenerator.finish();
|
|
188
169
|
async function getKey(keyId) {
|
|
189
170
|
const base64Key = Buffer.from(keyId).toString('base64');
|
|
171
|
+
const cached = derivedKeyCache.get(base64Key);
|
|
172
|
+
if (cached) {
|
|
173
|
+
return cached;
|
|
174
|
+
}
|
|
190
175
|
const keyEnc = await getAppStateSyncKey(base64Key);
|
|
191
176
|
if (!keyEnc) {
|
|
192
|
-
throw new
|
|
177
|
+
throw new Boom(`failed to find key "${base64Key}" to decode mutation`, {
|
|
178
|
+
statusCode: 404,
|
|
179
|
+
data: { msgMutations }
|
|
180
|
+
});
|
|
193
181
|
}
|
|
194
|
-
|
|
182
|
+
const keys = mutationKeys(keyEnc.keyData);
|
|
183
|
+
derivedKeyCache.set(base64Key, keys);
|
|
184
|
+
return keys;
|
|
195
185
|
}
|
|
196
186
|
};
|
|
197
|
-
|
|
198
|
-
const decodeSyncdPatch = async (msg, name, initialState, getAppStateSyncKey, onMutation, validateMacs) => {
|
|
187
|
+
export const decodeSyncdPatch = async (msg, name, initialState, getAppStateSyncKey, onMutation, validateMacs) => {
|
|
199
188
|
if (validateMacs) {
|
|
200
189
|
const base64Key = Buffer.from(msg.keyId.id).toString('base64');
|
|
201
190
|
const mainKeyObj = await getAppStateSyncKey(base64Key);
|
|
202
191
|
if (!mainKeyObj) {
|
|
203
|
-
throw new
|
|
192
|
+
throw new Boom(`failed to find key "${base64Key}" to decode patch`, { statusCode: 404, data: { msg } });
|
|
204
193
|
}
|
|
205
194
|
const mainKey = mutationKeys(mainKeyObj.keyData);
|
|
206
195
|
const mutationmacs = msg.mutations.map(mutation => mutation.record.value.blob.slice(-32));
|
|
207
|
-
const patchMac = generatePatchMac(msg.snapshotMac, mutationmacs,
|
|
196
|
+
const patchMac = generatePatchMac(msg.snapshotMac, mutationmacs, toNumber(msg.version.version), name, mainKey.patchMacKey);
|
|
208
197
|
if (Buffer.compare(patchMac, msg.patchMac) !== 0) {
|
|
209
|
-
throw new
|
|
198
|
+
throw new Boom('Invalid patch mac');
|
|
210
199
|
}
|
|
211
200
|
}
|
|
212
|
-
const result = await
|
|
201
|
+
const result = await decodeSyncdMutations(msg.mutations, initialState, getAppStateSyncKey, onMutation, validateMacs);
|
|
213
202
|
return result;
|
|
214
203
|
};
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
const
|
|
218
|
-
const collectionNodes = (0, WABinary_1.getBinaryNodeChildren)(syncNode, 'collection');
|
|
204
|
+
export const extractSyncdPatches = async (result, options) => {
|
|
205
|
+
const syncNode = getBinaryNodeChild(result, 'sync');
|
|
206
|
+
const collectionNodes = getBinaryNodeChildren(syncNode, 'collection');
|
|
219
207
|
const final = {};
|
|
220
208
|
await Promise.all(collectionNodes.map(async (collectionNode) => {
|
|
221
|
-
const patchesNode =
|
|
222
|
-
const patches =
|
|
223
|
-
const snapshotNode =
|
|
209
|
+
const patchesNode = getBinaryNodeChild(collectionNode, 'patches');
|
|
210
|
+
const patches = getBinaryNodeChildren(patchesNode || collectionNode, 'patch');
|
|
211
|
+
const snapshotNode = getBinaryNodeChild(collectionNode, 'snapshot');
|
|
224
212
|
const syncds = [];
|
|
225
213
|
const name = collectionNode.attrs.name;
|
|
226
214
|
const hasMorePatches = collectionNode.attrs.has_more_patches === 'true';
|
|
@@ -229,16 +217,16 @@ const extractSyncdPatches = async (result, options) => {
|
|
|
229
217
|
if (!Buffer.isBuffer(snapshotNode)) {
|
|
230
218
|
snapshotNode.content = Buffer.from(Object.values(snapshotNode.content));
|
|
231
219
|
}
|
|
232
|
-
const blobRef =
|
|
233
|
-
const data = await
|
|
234
|
-
snapshot =
|
|
220
|
+
const blobRef = proto.ExternalBlobReference.decode(snapshotNode.content);
|
|
221
|
+
const data = await downloadExternalBlob(blobRef, options);
|
|
222
|
+
snapshot = proto.SyncdSnapshot.decode(data);
|
|
235
223
|
}
|
|
236
224
|
for (let { content } of patches) {
|
|
237
225
|
if (content) {
|
|
238
226
|
if (!Buffer.isBuffer(content)) {
|
|
239
227
|
content = Buffer.from(Object.values(content));
|
|
240
228
|
}
|
|
241
|
-
const syncd =
|
|
229
|
+
const syncd = proto.SyncdPatch.decode(content);
|
|
242
230
|
if (!syncd.version) {
|
|
243
231
|
syncd.version = { version: +collectionNode.attrs.version + 1 };
|
|
244
232
|
}
|
|
@@ -249,32 +237,27 @@ const extractSyncdPatches = async (result, options) => {
|
|
|
249
237
|
}));
|
|
250
238
|
return final;
|
|
251
239
|
};
|
|
252
|
-
|
|
253
|
-
const
|
|
254
|
-
const stream = await (0, messages_media_1.downloadContentFromMessage)(blob, 'md-app-state', { options });
|
|
240
|
+
export const downloadExternalBlob = async (blob, options) => {
|
|
241
|
+
const stream = await downloadContentFromMessage(blob, 'md-app-state', { options });
|
|
255
242
|
const bufferArray = [];
|
|
256
243
|
for await (const chunk of stream) {
|
|
257
244
|
bufferArray.push(chunk);
|
|
258
245
|
}
|
|
259
246
|
return Buffer.concat(bufferArray);
|
|
260
247
|
};
|
|
261
|
-
|
|
262
|
-
const
|
|
263
|
-
const
|
|
264
|
-
const syncData = WAProto_1.proto.SyncdMutations.decode(buffer);
|
|
248
|
+
export const downloadExternalPatch = async (blob, options) => {
|
|
249
|
+
const buffer = await downloadExternalBlob(blob, options);
|
|
250
|
+
const syncData = proto.SyncdMutations.decode(buffer);
|
|
265
251
|
return syncData;
|
|
266
252
|
};
|
|
267
|
-
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
newState.version = (0, generics_1.toNumber)(snapshot.version.version);
|
|
253
|
+
export const decodeSyncdSnapshot = async (name, snapshot, getAppStateSyncKey, minimumVersionNumber, validateMacs = true) => {
|
|
254
|
+
const newState = newLTHashState();
|
|
255
|
+
newState.version = toNumber(snapshot.version.version);
|
|
271
256
|
const mutationMap = {};
|
|
272
|
-
const areMutationsRequired = typeof minimumVersionNumber === 'undefined'
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
var _a;
|
|
277
|
-
const index = (_a = mutation.syncAction.index) === null || _a === void 0 ? void 0 : _a.toString();
|
|
257
|
+
const areMutationsRequired = typeof minimumVersionNumber === 'undefined' || newState.version > minimumVersionNumber;
|
|
258
|
+
const { hash, indexValueMap } = await decodeSyncdMutations(snapshot.records, newState, getAppStateSyncKey, areMutationsRequired
|
|
259
|
+
? mutation => {
|
|
260
|
+
const index = mutation.syncAction.index?.toString();
|
|
278
261
|
mutationMap[index] = mutation;
|
|
279
262
|
}
|
|
280
263
|
: () => { }, validateMacs);
|
|
@@ -284,12 +267,12 @@ const decodeSyncdSnapshot = async (name, snapshot, getAppStateSyncKey, minimumVe
|
|
|
284
267
|
const base64Key = Buffer.from(snapshot.keyId.id).toString('base64');
|
|
285
268
|
const keyEnc = await getAppStateSyncKey(base64Key);
|
|
286
269
|
if (!keyEnc) {
|
|
287
|
-
throw new
|
|
270
|
+
throw new Boom(`failed to find key "${base64Key}" to decode mutation`);
|
|
288
271
|
}
|
|
289
272
|
const result = mutationKeys(keyEnc.keyData);
|
|
290
273
|
const computedSnapshotMac = generateSnapshotMac(newState.hash, newState.version, name, result.snapshotMacKey);
|
|
291
274
|
if (Buffer.compare(snapshot.mac, computedSnapshotMac) !== 0) {
|
|
292
|
-
throw new
|
|
275
|
+
throw new Boom(`failed to verify LTHash at ${newState.version} of ${name} from snapshot`);
|
|
293
276
|
}
|
|
294
277
|
}
|
|
295
278
|
return {
|
|
@@ -297,45 +280,41 @@ const decodeSyncdSnapshot = async (name, snapshot, getAppStateSyncKey, minimumVe
|
|
|
297
280
|
mutationMap
|
|
298
281
|
};
|
|
299
282
|
};
|
|
300
|
-
|
|
301
|
-
const decodePatches = async (name, syncds, initial, getAppStateSyncKey, options, minimumVersionNumber, logger, validateMacs = true) => {
|
|
302
|
-
var _a;
|
|
283
|
+
export const decodePatches = async (name, syncds, initial, getAppStateSyncKey, options, minimumVersionNumber, logger, validateMacs = true) => {
|
|
303
284
|
const newState = {
|
|
304
285
|
...initial,
|
|
305
286
|
indexValueMap: { ...initial.indexValueMap }
|
|
306
287
|
};
|
|
307
288
|
const mutationMap = {};
|
|
308
|
-
for (
|
|
309
|
-
const syncd = syncds[i];
|
|
289
|
+
for (const syncd of syncds) {
|
|
310
290
|
const { version, keyId, snapshotMac } = syncd;
|
|
311
291
|
if (syncd.externalMutations) {
|
|
312
|
-
logger
|
|
313
|
-
const ref = await
|
|
314
|
-
logger
|
|
315
|
-
|
|
292
|
+
logger?.trace({ name, version }, 'downloading external patch');
|
|
293
|
+
const ref = await downloadExternalPatch(syncd.externalMutations, options);
|
|
294
|
+
logger?.debug({ name, version, mutations: ref.mutations.length }, 'downloaded external patch');
|
|
295
|
+
syncd.mutations?.push(...ref.mutations);
|
|
316
296
|
}
|
|
317
|
-
const patchVersion =
|
|
297
|
+
const patchVersion = toNumber(version.version);
|
|
318
298
|
newState.version = patchVersion;
|
|
319
299
|
const shouldMutate = typeof minimumVersionNumber === 'undefined' || patchVersion > minimumVersionNumber;
|
|
320
|
-
const decodeResult = await
|
|
300
|
+
const decodeResult = await decodeSyncdPatch(syncd, name, newState, getAppStateSyncKey, shouldMutate
|
|
321
301
|
? mutation => {
|
|
322
|
-
|
|
323
|
-
const index = (_a = mutation.syncAction.index) === null || _a === void 0 ? void 0 : _a.toString();
|
|
302
|
+
const index = mutation.syncAction.index?.toString();
|
|
324
303
|
mutationMap[index] = mutation;
|
|
325
304
|
}
|
|
326
|
-
: (
|
|
305
|
+
: () => { }, true);
|
|
327
306
|
newState.hash = decodeResult.hash;
|
|
328
307
|
newState.indexValueMap = decodeResult.indexValueMap;
|
|
329
308
|
if (validateMacs) {
|
|
330
309
|
const base64Key = Buffer.from(keyId.id).toString('base64');
|
|
331
310
|
const keyEnc = await getAppStateSyncKey(base64Key);
|
|
332
311
|
if (!keyEnc) {
|
|
333
|
-
throw new
|
|
312
|
+
throw new Boom(`failed to find key "${base64Key}" to decode mutation`);
|
|
334
313
|
}
|
|
335
314
|
const result = mutationKeys(keyEnc.keyData);
|
|
336
315
|
const computedSnapshotMac = generateSnapshotMac(newState.hash, newState.version, name, result.snapshotMacKey);
|
|
337
316
|
if (Buffer.compare(snapshotMac, computedSnapshotMac) !== 0) {
|
|
338
|
-
throw new
|
|
317
|
+
throw new Boom(`failed to verify LTHash at ${newState.version} of ${name}`);
|
|
339
318
|
}
|
|
340
319
|
}
|
|
341
320
|
// clear memory used up by the mutations
|
|
@@ -343,31 +322,31 @@ const decodePatches = async (name, syncds, initial, getAppStateSyncKey, options,
|
|
|
343
322
|
}
|
|
344
323
|
return { state: newState, mutationMap };
|
|
345
324
|
};
|
|
346
|
-
|
|
347
|
-
const
|
|
348
|
-
const OP = WAProto_1.proto.SyncdMutation.SyncdOperation;
|
|
325
|
+
export const chatModificationToAppPatch = (mod, jid) => {
|
|
326
|
+
const OP = proto.SyncdMutation.SyncdOperation;
|
|
349
327
|
const getMessageRange = (lastMessages) => {
|
|
350
328
|
let messageRange;
|
|
351
329
|
if (Array.isArray(lastMessages)) {
|
|
352
330
|
const lastMsg = lastMessages[lastMessages.length - 1];
|
|
353
331
|
messageRange = {
|
|
354
|
-
lastMessageTimestamp: lastMsg
|
|
355
|
-
messages:
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
332
|
+
lastMessageTimestamp: lastMsg?.messageTimestamp,
|
|
333
|
+
messages: lastMessages?.length
|
|
334
|
+
? lastMessages.map(m => {
|
|
335
|
+
if (!m.key?.id || !m.key?.remoteJid) {
|
|
336
|
+
throw new Boom('Incomplete key', { statusCode: 400, data: m });
|
|
337
|
+
}
|
|
338
|
+
if (isJidGroup(m.key.remoteJid) && !m.key.fromMe && !m.key.participant) {
|
|
339
|
+
throw new Boom('Expected not from me message to have participant', { statusCode: 400, data: m });
|
|
340
|
+
}
|
|
341
|
+
if (!m.messageTimestamp || !toNumber(m.messageTimestamp)) {
|
|
342
|
+
throw new Boom('Missing timestamp in last message list', { statusCode: 400, data: m });
|
|
343
|
+
}
|
|
344
|
+
if (m.key.participant) {
|
|
345
|
+
m.key.participant = jidNormalizedUser(m.key.participant);
|
|
346
|
+
}
|
|
347
|
+
return m;
|
|
348
|
+
})
|
|
349
|
+
: undefined
|
|
371
350
|
};
|
|
372
351
|
}
|
|
373
352
|
else {
|
|
@@ -418,25 +397,33 @@ const chatModificationToAppPatch = (mod, jid) => {
|
|
|
418
397
|
operation: OP.SET
|
|
419
398
|
};
|
|
420
399
|
}
|
|
400
|
+
else if ('deleteForMe' in mod) {
|
|
401
|
+
const { timestamp, key, deleteMedia } = mod.deleteForMe;
|
|
402
|
+
patch = {
|
|
403
|
+
syncAction: {
|
|
404
|
+
deleteMessageForMeAction: {
|
|
405
|
+
deleteMedia,
|
|
406
|
+
messageTimestamp: timestamp
|
|
407
|
+
}
|
|
408
|
+
},
|
|
409
|
+
index: ['deleteMessageForMe', jid, key.id, key.fromMe ? '1' : '0', '0'],
|
|
410
|
+
type: 'regular_high',
|
|
411
|
+
apiVersion: 3,
|
|
412
|
+
operation: OP.SET
|
|
413
|
+
};
|
|
414
|
+
}
|
|
421
415
|
else if ('clear' in mod) {
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
},
|
|
434
|
-
index: ['deleteMessageForMe', jid, key.id, key.fromMe ? '1' : '0', '0'],
|
|
435
|
-
type: 'regular_high',
|
|
436
|
-
apiVersion: 3,
|
|
437
|
-
operation: OP.SET
|
|
438
|
-
};
|
|
439
|
-
}
|
|
416
|
+
patch = {
|
|
417
|
+
syncAction: {
|
|
418
|
+
clearChatAction: {
|
|
419
|
+
messageRange: getMessageRange(mod.lastMessages)
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
index: ['clearChat', jid, '1' /*the option here is 0 when keep starred messages is enabled*/, '0'],
|
|
423
|
+
type: 'regular_high',
|
|
424
|
+
apiVersion: 6,
|
|
425
|
+
operation: OP.SET
|
|
426
|
+
};
|
|
440
427
|
}
|
|
441
428
|
else if ('pin' in mod) {
|
|
442
429
|
patch = {
|
|
@@ -451,6 +438,28 @@ const chatModificationToAppPatch = (mod, jid) => {
|
|
|
451
438
|
operation: OP.SET
|
|
452
439
|
};
|
|
453
440
|
}
|
|
441
|
+
else if ('contact' in mod) {
|
|
442
|
+
patch = {
|
|
443
|
+
syncAction: {
|
|
444
|
+
contactAction: mod.contact || {}
|
|
445
|
+
},
|
|
446
|
+
index: ['contact', jid],
|
|
447
|
+
type: 'critical_unblock_low',
|
|
448
|
+
apiVersion: 2,
|
|
449
|
+
operation: mod.contact ? OP.SET : OP.REMOVE
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
else if ('disableLinkPreviews' in mod) {
|
|
453
|
+
patch = {
|
|
454
|
+
syncAction: {
|
|
455
|
+
privacySettingDisableLinkPreviewsAction: mod.disableLinkPreviews || {}
|
|
456
|
+
},
|
|
457
|
+
index: ['setting_disableLinkPreviews'],
|
|
458
|
+
type: 'regular',
|
|
459
|
+
apiVersion: 8,
|
|
460
|
+
operation: OP.SET
|
|
461
|
+
};
|
|
462
|
+
}
|
|
454
463
|
else if ('star' in mod) {
|
|
455
464
|
const key = mod.star.messages[0];
|
|
456
465
|
patch = {
|
|
@@ -469,7 +478,7 @@ const chatModificationToAppPatch = (mod, jid) => {
|
|
|
469
478
|
patch = {
|
|
470
479
|
syncAction: {
|
|
471
480
|
deleteChatAction: {
|
|
472
|
-
messageRange: getMessageRange(mod.lastMessages)
|
|
481
|
+
messageRange: getMessageRange(mod.lastMessages)
|
|
473
482
|
}
|
|
474
483
|
},
|
|
475
484
|
index: ['deleteChat', jid, '1'],
|
|
@@ -488,64 +497,90 @@ const chatModificationToAppPatch = (mod, jid) => {
|
|
|
488
497
|
index: ['setting_pushName'],
|
|
489
498
|
type: 'critical_block',
|
|
490
499
|
apiVersion: 1,
|
|
491
|
-
operation: OP.SET
|
|
500
|
+
operation: OP.SET
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
else if ('quickReply' in mod) {
|
|
504
|
+
patch = {
|
|
505
|
+
syncAction: {
|
|
506
|
+
quickReplyAction: {
|
|
507
|
+
count: 0,
|
|
508
|
+
deleted: mod.quickReply.deleted || false,
|
|
509
|
+
keywords: [],
|
|
510
|
+
message: mod.quickReply.message || '',
|
|
511
|
+
shortcut: mod.quickReply.shortcut || ''
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
index: ['quick_reply', mod.quickReply.timestamp || String(Math.floor(Date.now() / 1000))],
|
|
515
|
+
type: 'regular',
|
|
516
|
+
apiVersion: 2,
|
|
517
|
+
operation: OP.SET
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
else if ('addLabel' in mod) {
|
|
521
|
+
patch = {
|
|
522
|
+
syncAction: {
|
|
523
|
+
labelEditAction: {
|
|
524
|
+
name: mod.addLabel.name,
|
|
525
|
+
color: mod.addLabel.color,
|
|
526
|
+
predefinedId: mod.addLabel.predefinedId,
|
|
527
|
+
deleted: mod.addLabel.deleted
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
index: ['label_edit', mod.addLabel.id],
|
|
531
|
+
type: 'regular',
|
|
532
|
+
apiVersion: 3,
|
|
533
|
+
operation: OP.SET
|
|
492
534
|
};
|
|
493
535
|
}
|
|
494
536
|
else if ('addChatLabel' in mod) {
|
|
495
537
|
patch = {
|
|
496
538
|
syncAction: {
|
|
497
539
|
labelAssociationAction: {
|
|
498
|
-
labeled: true
|
|
540
|
+
labeled: true
|
|
499
541
|
}
|
|
500
542
|
},
|
|
501
|
-
index: [
|
|
543
|
+
index: [LabelAssociationType.Chat, mod.addChatLabel.labelId, jid],
|
|
502
544
|
type: 'regular',
|
|
503
545
|
apiVersion: 3,
|
|
504
|
-
operation: OP.SET
|
|
546
|
+
operation: OP.SET
|
|
505
547
|
};
|
|
506
548
|
}
|
|
507
549
|
else if ('removeChatLabel' in mod) {
|
|
508
550
|
patch = {
|
|
509
551
|
syncAction: {
|
|
510
552
|
labelAssociationAction: {
|
|
511
|
-
labeled: false
|
|
553
|
+
labeled: false
|
|
512
554
|
}
|
|
513
555
|
},
|
|
514
|
-
index: [
|
|
556
|
+
index: [LabelAssociationType.Chat, mod.removeChatLabel.labelId, jid],
|
|
515
557
|
type: 'regular',
|
|
516
558
|
apiVersion: 3,
|
|
517
|
-
operation: OP.SET
|
|
559
|
+
operation: OP.SET
|
|
518
560
|
};
|
|
519
561
|
}
|
|
520
562
|
else if ('addMessageLabel' in mod) {
|
|
521
563
|
patch = {
|
|
522
564
|
syncAction: {
|
|
523
565
|
labelAssociationAction: {
|
|
524
|
-
labeled: true
|
|
566
|
+
labeled: true
|
|
525
567
|
}
|
|
526
568
|
},
|
|
527
|
-
index: [
|
|
528
|
-
LabelAssociation_1.LabelAssociationType.Message,
|
|
529
|
-
mod.addMessageLabel.labelId,
|
|
530
|
-
jid,
|
|
531
|
-
mod.addMessageLabel.messageId,
|
|
532
|
-
'0',
|
|
533
|
-
'0'
|
|
534
|
-
],
|
|
569
|
+
index: [LabelAssociationType.Message, mod.addMessageLabel.labelId, jid, mod.addMessageLabel.messageId, '0', '0'],
|
|
535
570
|
type: 'regular',
|
|
536
571
|
apiVersion: 3,
|
|
537
|
-
operation: OP.SET
|
|
572
|
+
operation: OP.SET
|
|
538
573
|
};
|
|
539
574
|
}
|
|
540
575
|
else if ('removeMessageLabel' in mod) {
|
|
541
576
|
patch = {
|
|
542
577
|
syncAction: {
|
|
543
578
|
labelAssociationAction: {
|
|
544
|
-
labeled: false
|
|
579
|
+
labeled: false
|
|
545
580
|
}
|
|
546
581
|
},
|
|
547
582
|
index: [
|
|
548
|
-
|
|
583
|
+
LabelAssociationType.Message,
|
|
549
584
|
mod.removeMessageLabel.labelId,
|
|
550
585
|
jid,
|
|
551
586
|
mod.removeMessageLabel.messageId,
|
|
@@ -554,34 +589,30 @@ const chatModificationToAppPatch = (mod, jid) => {
|
|
|
554
589
|
],
|
|
555
590
|
type: 'regular',
|
|
556
591
|
apiVersion: 3,
|
|
557
|
-
operation: OP.SET
|
|
592
|
+
operation: OP.SET
|
|
558
593
|
};
|
|
559
594
|
}
|
|
560
595
|
else {
|
|
561
|
-
throw new
|
|
596
|
+
throw new Boom('not supported');
|
|
562
597
|
}
|
|
563
598
|
patch.syncAction.timestamp = Date.now();
|
|
564
599
|
return patch;
|
|
565
600
|
};
|
|
566
|
-
|
|
567
|
-
const processSyncAction = (syncAction, ev, me, initialSyncOpts, logger) => {
|
|
568
|
-
var _a, _b, _c, _d;
|
|
601
|
+
export const processSyncAction = (syncAction, ev, me, initialSyncOpts, logger) => {
|
|
569
602
|
const isInitialSync = !!initialSyncOpts;
|
|
570
|
-
const accountSettings = initialSyncOpts
|
|
571
|
-
logger
|
|
603
|
+
const accountSettings = initialSyncOpts?.accountSettings;
|
|
604
|
+
logger?.trace({ syncAction, initialSync: !!initialSyncOpts }, 'processing sync action');
|
|
572
605
|
const { syncAction: { value: action }, index: [type, id, msgId, fromMe] } = syncAction;
|
|
573
|
-
if (action
|
|
606
|
+
if (action?.muteAction) {
|
|
574
607
|
ev.emit('chats.update', [
|
|
575
608
|
{
|
|
576
609
|
id,
|
|
577
|
-
muteEndTime:
|
|
578
|
-
? (0, generics_1.toNumber)(action.muteAction.muteEndTimestamp)
|
|
579
|
-
: null,
|
|
610
|
+
muteEndTime: action.muteAction?.muted ? toNumber(action.muteAction.muteEndTimestamp) : null,
|
|
580
611
|
conditional: getChatUpdateConditional(id, undefined)
|
|
581
612
|
}
|
|
582
613
|
]);
|
|
583
614
|
}
|
|
584
|
-
else if (
|
|
615
|
+
else if (action?.archiveChatAction || type === 'archive' || type === 'unarchive') {
|
|
585
616
|
// okay so we've to do some annoying computation here
|
|
586
617
|
// when we're initially syncing the app state
|
|
587
618
|
// there are a few cases we need to handle
|
|
@@ -592,36 +623,38 @@ const processSyncAction = (syncAction, ev, me, initialSyncOpts, logger) => {
|
|
|
592
623
|
// we compare the timestamp of latest message from the other person to determine this
|
|
593
624
|
// 2. if the account unarchiveChats setting is false -- then it doesn't matter,
|
|
594
625
|
// it'll always take an app state action to mark in unarchived -- which we'll get anyway
|
|
595
|
-
const archiveAction = action
|
|
596
|
-
const isArchived = archiveAction
|
|
597
|
-
? archiveAction.archived
|
|
598
|
-
: type === 'archive';
|
|
626
|
+
const archiveAction = action?.archiveChatAction;
|
|
627
|
+
const isArchived = archiveAction ? archiveAction.archived : type === 'archive';
|
|
599
628
|
// // basically we don't need to fire an "archive" update if the chat is being marked unarchvied
|
|
600
629
|
// // this only applies for the initial sync
|
|
601
630
|
// if(isInitialSync && !isArchived) {
|
|
602
631
|
// isArchived = false
|
|
603
632
|
// }
|
|
604
|
-
const msgRange = !
|
|
633
|
+
const msgRange = !accountSettings?.unarchiveChats ? undefined : archiveAction?.messageRange;
|
|
605
634
|
// logger?.debug({ chat: id, syncAction }, 'message range archive')
|
|
606
|
-
ev.emit('chats.update', [
|
|
635
|
+
ev.emit('chats.update', [
|
|
636
|
+
{
|
|
607
637
|
id,
|
|
608
638
|
archived: isArchived,
|
|
609
639
|
conditional: getChatUpdateConditional(id, msgRange)
|
|
610
|
-
}
|
|
640
|
+
}
|
|
641
|
+
]);
|
|
611
642
|
}
|
|
612
|
-
else if (action
|
|
643
|
+
else if (action?.markChatAsReadAction) {
|
|
613
644
|
const markReadAction = action.markChatAsReadAction;
|
|
614
645
|
// basically we don't need to fire an "read" update if the chat is being marked as read
|
|
615
646
|
// because the chat is read by default
|
|
616
647
|
// this only applies for the initial sync
|
|
617
648
|
const isNullUpdate = isInitialSync && markReadAction.read;
|
|
618
|
-
ev.emit('chats.update', [
|
|
649
|
+
ev.emit('chats.update', [
|
|
650
|
+
{
|
|
619
651
|
id,
|
|
620
|
-
unreadCount: isNullUpdate ? null : !!
|
|
621
|
-
conditional: getChatUpdateConditional(id, markReadAction
|
|
622
|
-
}
|
|
652
|
+
unreadCount: isNullUpdate ? null : !!markReadAction?.read ? 0 : -1,
|
|
653
|
+
conditional: getChatUpdateConditional(id, markReadAction?.messageRange)
|
|
654
|
+
}
|
|
655
|
+
]);
|
|
623
656
|
}
|
|
624
|
-
else if (
|
|
657
|
+
else if (action?.deleteMessageForMeAction || type === 'deleteMessageForMe') {
|
|
625
658
|
ev.emit('messages.delete', {
|
|
626
659
|
keys: [
|
|
627
660
|
{
|
|
@@ -632,37 +665,35 @@ const processSyncAction = (syncAction, ev, me, initialSyncOpts, logger) => {
|
|
|
632
665
|
]
|
|
633
666
|
});
|
|
634
667
|
}
|
|
635
|
-
else if (action
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
}
|
|
643
|
-
else if (action === null || action === void 0 ? void 0 : action.pushNameSetting) {
|
|
644
|
-
const name = (_b = action === null || action === void 0 ? void 0 : action.pushNameSetting) === null || _b === void 0 ? void 0 : _b.name;
|
|
645
|
-
if (name && (me === null || me === void 0 ? void 0 : me.name) !== name) {
|
|
668
|
+
else if (action?.contactAction) {
|
|
669
|
+
const results = processContactAction(action.contactAction, id, logger);
|
|
670
|
+
emitSyncActionResults(ev, results);
|
|
671
|
+
}
|
|
672
|
+
else if (action?.pushNameSetting) {
|
|
673
|
+
const name = action?.pushNameSetting?.name;
|
|
674
|
+
if (name && me?.name !== name) {
|
|
646
675
|
ev.emit('creds.update', { me: { ...me, name } });
|
|
647
676
|
}
|
|
648
677
|
}
|
|
649
|
-
else if (action
|
|
650
|
-
ev.emit('chats.update', [
|
|
678
|
+
else if (action?.pinAction) {
|
|
679
|
+
ev.emit('chats.update', [
|
|
680
|
+
{
|
|
651
681
|
id,
|
|
652
|
-
pinned:
|
|
682
|
+
pinned: action.pinAction?.pinned ? toNumber(action.timestamp) : null,
|
|
653
683
|
conditional: getChatUpdateConditional(id, undefined)
|
|
654
|
-
}
|
|
684
|
+
}
|
|
685
|
+
]);
|
|
655
686
|
}
|
|
656
|
-
else if (action
|
|
687
|
+
else if (action?.unarchiveChatsSetting) {
|
|
657
688
|
const unarchiveChats = !!action.unarchiveChatsSetting.unarchiveChats;
|
|
658
689
|
ev.emit('creds.update', { accountSettings: { unarchiveChats } });
|
|
659
|
-
logger
|
|
690
|
+
logger?.info(`archive setting updated => '${action.unarchiveChatsSetting.unarchiveChats}'`);
|
|
660
691
|
if (accountSettings) {
|
|
661
692
|
accountSettings.unarchiveChats = unarchiveChats;
|
|
662
693
|
}
|
|
663
694
|
}
|
|
664
|
-
else if (
|
|
665
|
-
let starred =
|
|
695
|
+
else if (action?.starAction || type === 'star') {
|
|
696
|
+
let starred = action?.starAction?.starred;
|
|
666
697
|
if (typeof starred !== 'boolean') {
|
|
667
698
|
starred = syncAction.index[syncAction.index.length - 1] === '1';
|
|
668
699
|
}
|
|
@@ -673,46 +704,98 @@ const processSyncAction = (syncAction, ev, me, initialSyncOpts, logger) => {
|
|
|
673
704
|
}
|
|
674
705
|
]);
|
|
675
706
|
}
|
|
676
|
-
else if (
|
|
707
|
+
else if (action?.deleteChatAction || type === 'deleteChat') {
|
|
677
708
|
if (!isInitialSync) {
|
|
678
709
|
ev.emit('chats.delete', [id]);
|
|
679
710
|
}
|
|
680
711
|
}
|
|
681
|
-
else if (action
|
|
712
|
+
else if (action?.labelEditAction) {
|
|
682
713
|
const { name, color, deleted, predefinedId } = action.labelEditAction;
|
|
683
714
|
ev.emit('labels.edit', {
|
|
684
|
-
id,
|
|
715
|
+
id: id,
|
|
685
716
|
name: name,
|
|
686
717
|
color: color,
|
|
687
718
|
deleted: deleted,
|
|
688
719
|
predefinedId: predefinedId ? String(predefinedId) : undefined
|
|
689
720
|
});
|
|
690
721
|
}
|
|
691
|
-
else if (action
|
|
722
|
+
else if (action?.labelAssociationAction) {
|
|
692
723
|
ev.emit('labels.association', {
|
|
693
|
-
type: action.labelAssociationAction.labeled
|
|
694
|
-
|
|
695
|
-
: 'remove',
|
|
696
|
-
association: type === LabelAssociation_1.LabelAssociationType.Chat
|
|
724
|
+
type: action.labelAssociationAction.labeled ? 'add' : 'remove',
|
|
725
|
+
association: type === LabelAssociationType.Chat
|
|
697
726
|
? {
|
|
698
|
-
type:
|
|
727
|
+
type: LabelAssociationType.Chat,
|
|
699
728
|
chatId: syncAction.index[2],
|
|
700
729
|
labelId: syncAction.index[1]
|
|
701
730
|
}
|
|
702
731
|
: {
|
|
703
|
-
type:
|
|
732
|
+
type: LabelAssociationType.Message,
|
|
704
733
|
chatId: syncAction.index[2],
|
|
705
734
|
messageId: syncAction.index[3],
|
|
706
735
|
labelId: syncAction.index[1]
|
|
707
736
|
}
|
|
708
737
|
});
|
|
709
738
|
}
|
|
739
|
+
else if (action?.localeSetting?.locale) {
|
|
740
|
+
ev.emit('settings.update', { setting: 'locale', value: action.localeSetting.locale });
|
|
741
|
+
}
|
|
742
|
+
else if (action?.timeFormatAction) {
|
|
743
|
+
ev.emit('settings.update', { setting: 'timeFormat', value: action.timeFormatAction });
|
|
744
|
+
}
|
|
745
|
+
else if (action?.pnForLidChatAction) {
|
|
746
|
+
if (action.pnForLidChatAction.pnJid) {
|
|
747
|
+
ev.emit('lid-mapping.update', { lid: id, pn: action.pnForLidChatAction.pnJid });
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
else if (action?.privacySettingRelayAllCalls) {
|
|
751
|
+
ev.emit('settings.update', {
|
|
752
|
+
setting: 'privacySettingRelayAllCalls',
|
|
753
|
+
value: action.privacySettingRelayAllCalls
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
else if (action?.statusPrivacy) {
|
|
757
|
+
ev.emit('settings.update', { setting: 'statusPrivacy', value: action.statusPrivacy });
|
|
758
|
+
}
|
|
759
|
+
else if (action?.lockChatAction) {
|
|
760
|
+
ev.emit('chats.lock', { id: id, locked: !!action.lockChatAction.locked });
|
|
761
|
+
}
|
|
762
|
+
else if (action?.privacySettingDisableLinkPreviewsAction) {
|
|
763
|
+
ev.emit('settings.update', {
|
|
764
|
+
setting: 'disableLinkPreviews',
|
|
765
|
+
value: action.privacySettingDisableLinkPreviewsAction
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
else if (action?.notificationActivitySettingAction?.notificationActivitySetting) {
|
|
769
|
+
ev.emit('settings.update', {
|
|
770
|
+
setting: 'notificationActivitySetting',
|
|
771
|
+
value: action.notificationActivitySettingAction.notificationActivitySetting
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
else if (action?.lidContactAction) {
|
|
775
|
+
ev.emit('contacts.upsert', [
|
|
776
|
+
{
|
|
777
|
+
id: id,
|
|
778
|
+
name: action.lidContactAction.fullName ||
|
|
779
|
+
action.lidContactAction.firstName ||
|
|
780
|
+
action.lidContactAction.username ||
|
|
781
|
+
undefined,
|
|
782
|
+
lid: id,
|
|
783
|
+
phoneNumber: undefined
|
|
784
|
+
}
|
|
785
|
+
]);
|
|
786
|
+
}
|
|
787
|
+
else if (action?.privacySettingChannelsPersonalisedRecommendationAction) {
|
|
788
|
+
ev.emit('settings.update', {
|
|
789
|
+
setting: 'channelsPersonalisedRecommendation',
|
|
790
|
+
value: action.privacySettingChannelsPersonalisedRecommendationAction
|
|
791
|
+
});
|
|
792
|
+
}
|
|
710
793
|
else {
|
|
711
|
-
logger
|
|
794
|
+
logger?.debug({ syncAction, id }, 'unprocessable update');
|
|
712
795
|
}
|
|
713
796
|
function getChatUpdateConditional(id, msgRange) {
|
|
714
797
|
return isInitialSync
|
|
715
|
-
?
|
|
798
|
+
? data => {
|
|
716
799
|
const chat = data.historySets.chats[id] || data.chatUpserts[id];
|
|
717
800
|
if (chat) {
|
|
718
801
|
return msgRange ? isValidPatchBasedOnMessageRange(chat, msgRange) : true;
|
|
@@ -721,9 +804,8 @@ const processSyncAction = (syncAction, ev, me, initialSyncOpts, logger) => {
|
|
|
721
804
|
: undefined;
|
|
722
805
|
}
|
|
723
806
|
function isValidPatchBasedOnMessageRange(chat, msgRange) {
|
|
724
|
-
const lastMsgTimestamp = Number(
|
|
725
|
-
const chatLastMsgTimestamp = Number(
|
|
807
|
+
const lastMsgTimestamp = Number(msgRange?.lastMessageTimestamp || msgRange?.lastSystemMessageTimestamp || 0);
|
|
808
|
+
const chatLastMsgTimestamp = Number(chat?.lastMessageRecvTimestamp || 0);
|
|
726
809
|
return lastMsgTimestamp >= chatLastMsgTimestamp;
|
|
727
810
|
}
|
|
728
|
-
};
|
|
729
|
-
exports.processSyncAction = processSyncAction;
|
|
811
|
+
};
|