@celestial-community/baileys 0.0.1-security → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of @celestial-community/baileys might be problematic. Click here for more details.

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