@pontalabs/baileys 1.0.11 → 1.1.0

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