@pontalabs/baileys 1.0.6 → 1.0.7

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