@bellaxchuu/flowred 0.8.6

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 (142) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +214 -0
  3. package/WAProto/GenerateStatics.sh +3 -0
  4. package/WAProto/WAProto.proto +6902 -0
  5. package/WAProto/fix-imports.js +85 -0
  6. package/WAProto/index.js +242946 -0
  7. package/engine-requirements.js +10 -0
  8. package/lib/Defaults/index.js +190 -0
  9. package/lib/Defaults/phonenumber-mcc.json +223 -0
  10. package/lib/Signal/Group/ciphertext-message.js +15 -0
  11. package/lib/Signal/Group/group-session-builder.js +92 -0
  12. package/lib/Signal/Group/group_cipher.js +89 -0
  13. package/lib/Signal/Group/index.js +136 -0
  14. package/lib/Signal/Group/keyhelper.js +73 -0
  15. package/lib/Signal/Group/sender-chain-key.js +32 -0
  16. package/lib/Signal/Group/sender-key-distribution-message.js +66 -0
  17. package/lib/Signal/Group/sender-key-message.js +69 -0
  18. package/lib/Signal/Group/sender-key-name.js +50 -0
  19. package/lib/Signal/Group/sender-key-record.js +44 -0
  20. package/lib/Signal/Group/sender-key-state.js +97 -0
  21. package/lib/Signal/Group/sender-message-key.js +30 -0
  22. package/lib/Signal/libsignal.js +490 -0
  23. package/lib/Signal/lid-mapping.js +262 -0
  24. package/lib/Socket/Client/index.js +30 -0
  25. package/lib/Socket/Client/types.js +13 -0
  26. package/lib/Socket/Client/websocket.js +62 -0
  27. package/lib/Socket/aigroups.js +240 -0
  28. package/lib/Socket/business.js +422 -0
  29. package/lib/Socket/chats.js +1816 -0
  30. package/lib/Socket/communities.js +549 -0
  31. package/lib/Socket/graphql.js +656 -0
  32. package/lib/Socket/groups.js +764 -0
  33. package/lib/Socket/index.js +39 -0
  34. package/lib/Socket/interactive-handler.js +522 -0
  35. package/lib/Socket/interop.js +549 -0
  36. package/lib/Socket/luxu.js +387 -0
  37. package/lib/Socket/managed-account.js +183 -0
  38. package/lib/Socket/messages-recv.js +2440 -0
  39. package/lib/Socket/messages-send.js +1853 -0
  40. package/lib/Socket/mex.js +60 -0
  41. package/lib/Socket/newsletter.js +820 -0
  42. package/lib/Socket/privacy.js +449 -0
  43. package/lib/Socket/registration.js +427 -0
  44. package/lib/Socket/socket.js +1092 -0
  45. package/lib/Socket/text-router.js +83 -0
  46. package/lib/Socket/username.js +243 -0
  47. package/lib/Store/index.js +36 -0
  48. package/lib/Store/keyed-db.js +108 -0
  49. package/lib/Store/make-cache-manager-store.js +90 -0
  50. package/lib/Store/make-in-memory-store.js +604 -0
  51. package/lib/Store/make-ordered-dictionary.js +81 -0
  52. package/lib/Store/object-repository.js +29 -0
  53. package/lib/Types/Auth.js +38 -0
  54. package/lib/Types/Bussines.js +2 -0
  55. package/lib/Types/Call.js +2 -0
  56. package/lib/Types/Chat.js +4 -0
  57. package/lib/Types/Contact.js +2 -0
  58. package/lib/Types/Events.js +2 -0
  59. package/lib/Types/GroupMetadata.js +2 -0
  60. package/lib/Types/Label.js +27 -0
  61. package/lib/Types/LabelAssociation.js +9 -0
  62. package/lib/Types/Message.js +95 -0
  63. package/lib/Types/Mex.js +112 -0
  64. package/lib/Types/Newsletter.js +121 -0
  65. package/lib/Types/Product.js +2 -0
  66. package/lib/Types/Signal.js +2 -0
  67. package/lib/Types/Socket.js +2 -0
  68. package/lib/Types/State.js +70 -0
  69. package/lib/Types/USync.js +2 -0
  70. package/lib/Types/index.js +55 -0
  71. package/lib/Utils/auth-utils.js +306 -0
  72. package/lib/Utils/browser-utils.js +114 -0
  73. package/lib/Utils/business.js +247 -0
  74. package/lib/Utils/chat-utils.js +1208 -0
  75. package/lib/Utils/command-loader.js +100 -0
  76. package/lib/Utils/companion-reg-client-utils.js +42 -0
  77. package/lib/Utils/consumer-application.js +107 -0
  78. package/lib/Utils/crypto.js +155 -0
  79. package/lib/Utils/curve25519-js.js +275 -0
  80. package/lib/Utils/decode-wa-message.js +560 -0
  81. package/lib/Utils/event-buffer.js +607 -0
  82. package/lib/Utils/generics.js +563 -0
  83. package/lib/Utils/group-history.js +60 -0
  84. package/lib/Utils/history.js +244 -0
  85. package/lib/Utils/identity-change-handler.js +52 -0
  86. package/lib/Utils/index.js +57 -0
  87. package/lib/Utils/jid-display-normalization.js +218 -0
  88. package/lib/Utils/link-preview.js +143 -0
  89. package/lib/Utils/logger.js +9 -0
  90. package/lib/Utils/lt-hash.js +39 -0
  91. package/lib/Utils/make-mutex.js +36 -0
  92. package/lib/Utils/message-composer.js +479 -0
  93. package/lib/Utils/message-retry-manager.js +270 -0
  94. package/lib/Utils/messages-media.js +896 -0
  95. package/lib/Utils/messages.js +2904 -0
  96. package/lib/Utils/meta-ai-msmsg.js +262 -0
  97. package/lib/Utils/native-bridge.js +82 -0
  98. package/lib/Utils/noise-handler.js +196 -0
  99. package/lib/Utils/offline-node-processor.js +42 -0
  100. package/lib/Utils/pre-key-manager.js +107 -0
  101. package/lib/Utils/process-message.js +1048 -0
  102. package/lib/Utils/reporting-utils.js +262 -0
  103. package/lib/Utils/session-pool.js +94 -0
  104. package/lib/Utils/signal.js +224 -0
  105. package/lib/Utils/stanza-ack.js +40 -0
  106. package/lib/Utils/sticker.js +145 -0
  107. package/lib/Utils/sync-action-utils.js +54 -0
  108. package/lib/Utils/tc-token-utils.js +161 -0
  109. package/lib/Utils/use-multi-file-auth-state.js +121 -0
  110. package/lib/Utils/validate-connection.js +219 -0
  111. package/lib/Utils/view-once-cache.js +79 -0
  112. package/lib/Utils/voip-rekey.js +22 -0
  113. package/lib/WABinary/constants.js +1304 -0
  114. package/lib/WABinary/decode.js +343 -0
  115. package/lib/WABinary/encode.js +228 -0
  116. package/lib/WABinary/generic-utils.js +240 -0
  117. package/lib/WABinary/index.js +33 -0
  118. package/lib/WABinary/jid-utils.js +361 -0
  119. package/lib/WABinary/types.js +2 -0
  120. package/lib/WAM/BinaryInfo.js +13 -0
  121. package/lib/WAM/constants.js +39486 -0
  122. package/lib/WAM/encode.js +142 -0
  123. package/lib/WAM/index.js +31 -0
  124. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +55 -0
  125. package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +43 -0
  126. package/lib/WAUSync/Protocols/USyncContactProtocol.js +54 -0
  127. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +57 -0
  128. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +30 -0
  129. package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +59 -0
  130. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +31 -0
  131. package/lib/WAUSync/Protocols/USyncPictureProtocol.js +32 -0
  132. package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +29 -0
  133. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +39 -0
  134. package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +38 -0
  135. package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +27 -0
  136. package/lib/WAUSync/Protocols/index.js +39 -0
  137. package/lib/WAUSync/USyncQuery.js +133 -0
  138. package/lib/WAUSync/USyncUser.js +50 -0
  139. package/lib/WAUSync/index.js +31 -0
  140. package/lib/antiban.js +4637 -0
  141. package/lib/index.js +45 -0
  142. package/package.json +107 -0
@@ -0,0 +1,1048 @@
1
+ 'use strict'
2
+ Object.defineProperty(exports, '__esModule', { value: true })
3
+ exports.getChatId = exports.shouldIncrementChatUnread = exports.isRealMessage = exports.cleanMessage = void 0
4
+ exports.decryptPollVote = decryptPollVote
5
+ exports.decryptEventResponse = decryptEventResponse
6
+ const index_js_1 = require('../../WAProto/index.js')
7
+ const Types_1 = require('../Types')
8
+ const messages_1 = require('../Utils/messages')
9
+ const WABinary_1 = require('../WABinary')
10
+ const crypto_1 = require('./crypto')
11
+ const generics_1 = require('./generics')
12
+ const history_1 = require('./history')
13
+ const tc_token_utils_1 = require('./tc-token-utils')
14
+ async function storeTcTokensFromHistorySync(chats, signalRepository, keyStore, logger) {
15
+ const getLIDForPN = signalRepository.lidMapping.getLIDForPN.bind(signalRepository.lidMapping)
16
+ const candidates = []
17
+ for (const chat of chats) {
18
+ const ts = chat.tcTokenTimestamp ? (0, generics_1.toNumber)(chat.tcTokenTimestamp) : 0
19
+ if (chat.tcToken?.length && ts > 0) {
20
+ const jid = (0, WABinary_1.jidNormalizedUser)(chat.id)
21
+ const storageJid = await (0, tc_token_utils_1.resolveTcTokenJid)(jid, getLIDForPN)
22
+ candidates.push({
23
+ storageJid,
24
+ token: Buffer.from(chat.tcToken),
25
+ ts,
26
+ senderTs: chat.tcTokenSenderTimestamp ? (0, generics_1.toNumber)(chat.tcTokenSenderTimestamp) : undefined
27
+ })
28
+ }
29
+ }
30
+ if (!candidates.length) return
31
+ const jids = candidates.map(c => c.storageJid)
32
+ const existing = await keyStore.get('tctoken', jids)
33
+ const entries = {}
34
+ for (const c of candidates) {
35
+ const existingEntry = existing[c.storageJid]
36
+ const existingTs = existingEntry?.timestamp ? Number(existingEntry.timestamp) : 0
37
+ if (existingTs > 0 && existingTs >= c.ts) continue
38
+ entries[c.storageJid] = {
39
+ ...existingEntry,
40
+ token: c.token,
41
+ timestamp: String(c.ts),
42
+ ...(c.senderTs !== undefined ? { senderTimestamp: c.senderTs } : {})
43
+ }
44
+ }
45
+ if (Object.keys(entries).length) {
46
+ logger?.debug({ count: Object.keys(entries).length }, 'storing tctokens from history sync')
47
+ try {
48
+ const indexWrite = await (0, tc_token_utils_1.buildMergedTcTokenIndexWrite)(keyStore, Object.keys(entries))
49
+ await keyStore.set({ tctoken: { ...entries, ...indexWrite } })
50
+ } catch (err) {
51
+ logger?.warn({ err }, 'failed to store tctokens from history sync')
52
+ }
53
+ }
54
+ }
55
+ const REAL_MSG_STUB_TYPES = new Set([
56
+ Types_1.WAMessageStubType.CALL_MISSED_GROUP_VIDEO,
57
+ Types_1.WAMessageStubType.CALL_MISSED_GROUP_VOICE,
58
+ Types_1.WAMessageStubType.CALL_MISSED_VIDEO,
59
+ Types_1.WAMessageStubType.CALL_MISSED_VOICE
60
+ ])
61
+ const REAL_MSG_REQ_ME_STUB_TYPES = new Set([Types_1.WAMessageStubType.GROUP_PARTICIPANT_ADD])
62
+ /** Cleans a received message to further processing */
63
+ const cleanMessage = (message, meId, meLid) => {
64
+ // ensure remoteJid and participant doesn't have device or agent in it
65
+ if ((0, WABinary_1.isHostedPnUser)(message.key.remoteJid) || (0, WABinary_1.isHostedLidUser)(message.key.remoteJid)) {
66
+ message.key.remoteJid = (0, WABinary_1.jidEncode)(
67
+ (0, WABinary_1.jidDecode)(message.key?.remoteJid)?.user,
68
+ (0, WABinary_1.isHostedPnUser)(message.key.remoteJid) ? 's.whatsapp.net' : 'lid'
69
+ )
70
+ } else {
71
+ message.key.remoteJid = (0, WABinary_1.jidNormalizedUser)(message.key.remoteJid)
72
+ }
73
+ if (
74
+ (0, WABinary_1.isHostedPnUser)(message.key.participant) ||
75
+ (0, WABinary_1.isHostedLidUser)(message.key.participant)
76
+ ) {
77
+ message.key.participant = (0, WABinary_1.jidEncode)(
78
+ (0, WABinary_1.jidDecode)(message.key.participant)?.user,
79
+ (0, WABinary_1.isHostedPnUser)(message.key.participant) ? 's.whatsapp.net' : 'lid'
80
+ )
81
+ } else {
82
+ message.key.participant = (0, WABinary_1.jidNormalizedUser)(message.key.participant)
83
+ }
84
+ const content = (0, messages_1.normalizeMessageContent)(message.message)
85
+ // if the message has a reaction, ensure fromMe & remoteJid are from our perspective
86
+ if (content?.reactionMessage) {
87
+ normaliseKey(content.reactionMessage.key)
88
+ }
89
+ if (content?.pollUpdateMessage) {
90
+ normaliseKey(content.pollUpdateMessage.pollCreationMessageKey)
91
+ }
92
+ function normaliseKey(msgKey) {
93
+ // if the reaction is from another user
94
+ // we've to correctly map the key to this user's perspective
95
+ if (!message.key.fromMe) {
96
+ // if the sender believed the message being reacted to is not from them
97
+ // we've to correct the key to be from them, or some other participant
98
+ msgKey.fromMe = !msgKey.fromMe
99
+ ? (0, WABinary_1.areJidsSameUser)(msgKey.participant || msgKey.remoteJid, meId) ||
100
+ (0, WABinary_1.areJidsSameUser)(msgKey.participant || msgKey.remoteJid, meLid)
101
+ : // if the message being reacted to, was from them
102
+ // fromMe automatically becomes false
103
+ false
104
+ // set the remoteJid to being the same as the chat the message came from
105
+ // TODO: investigate inconsistencies
106
+ msgKey.remoteJid = message.key.remoteJid
107
+ // set participant of the message
108
+ msgKey.participant = msgKey.participant || message.key.participant
109
+ }
110
+ }
111
+ }
112
+ exports.cleanMessage = cleanMessage
113
+ // TODO: target:audit AUDIT THIS FUNCTION AGAIN
114
+ const isRealMessage = message => {
115
+ const normalizedContent = (0, messages_1.normalizeMessageContent)(message.message)
116
+ const hasSomeContent = !!(0, messages_1.getContentType)(normalizedContent)
117
+ return (
118
+ (!!normalizedContent ||
119
+ REAL_MSG_STUB_TYPES.has(message.messageStubType) ||
120
+ REAL_MSG_REQ_ME_STUB_TYPES.has(message.messageStubType)) &&
121
+ hasSomeContent &&
122
+ !normalizedContent?.protocolMessage &&
123
+ !normalizedContent?.reactionMessage &&
124
+ !normalizedContent?.pollUpdateMessage
125
+ )
126
+ }
127
+ exports.isRealMessage = isRealMessage
128
+ const shouldIncrementChatUnread = message => !message.key.fromMe && !message.messageStubType
129
+ exports.shouldIncrementChatUnread = shouldIncrementChatUnread
130
+ /**
131
+ * Get the ID of the chat from the given key.
132
+ * Typically -- that'll be the remoteJid, but for broadcasts, it'll be the participant
133
+ */
134
+ const getChatId = ({ remoteJid, participant, fromMe }) => {
135
+ if ((0, WABinary_1.isJidBroadcast)(remoteJid) && !(0, WABinary_1.isJidStatusBroadcast)(remoteJid) && !fromMe) {
136
+ return participant
137
+ }
138
+ return remoteJid
139
+ }
140
+ exports.getChatId = getChatId
141
+ /**
142
+ * Decrypt a poll vote
143
+ * @param vote encrypted vote
144
+ * @param ctx additional info about the poll required for decryption
145
+ * @returns list of SHA256 options
146
+ */
147
+ function decryptPollVote({ encPayload, encIv }, { pollCreatorJid, pollMsgId, pollEncKey, voterJid }) {
148
+ const sign = Buffer.concat([
149
+ toBinary(pollMsgId),
150
+ toBinary(pollCreatorJid),
151
+ toBinary(voterJid),
152
+ toBinary('Poll Vote'),
153
+ new Uint8Array([1])
154
+ ])
155
+ const key0 = (0, crypto_1.hmacSign)(pollEncKey, new Uint8Array(32), 'sha256')
156
+ const decKey = (0, crypto_1.hmacSign)(sign, key0, 'sha256')
157
+ const aad = toBinary(`${pollMsgId}\u0000${voterJid}`)
158
+ const decrypted = (0, crypto_1.aesDecryptGCM)(encPayload, decKey, encIv, aad)
159
+ return index_js_1.proto.Message.PollVoteMessage.decode(decrypted)
160
+ function toBinary(txt) {
161
+ return Buffer.from(txt)
162
+ }
163
+ }
164
+ /**
165
+ * Decrypt an event response
166
+ * @param response encrypted event response
167
+ * @param ctx additional info about the event required for decryption
168
+ * @returns event response message
169
+ */
170
+ function decryptEventResponse({ encPayload, encIv }, { eventCreatorJid, eventMsgId, eventEncKey, responderJid }) {
171
+ const sign = Buffer.concat([
172
+ toBinary(eventMsgId),
173
+ toBinary(eventCreatorJid),
174
+ toBinary(responderJid),
175
+ toBinary('Event Response'),
176
+ new Uint8Array([1])
177
+ ])
178
+ const key0 = (0, crypto_1.hmacSign)(eventEncKey, new Uint8Array(32), 'sha256')
179
+ const decKey = (0, crypto_1.hmacSign)(sign, key0, 'sha256')
180
+ const aad = toBinary(`${eventMsgId}\u0000${responderJid}`)
181
+ const decrypted = (0, crypto_1.aesDecryptGCM)(encPayload, decKey, encIv, aad)
182
+ return index_js_1.proto.Message.EventResponseMessage.decode(decrypted)
183
+ function toBinary(txt) {
184
+ return Buffer.from(txt)
185
+ }
186
+ }
187
+ const processMessage = async (
188
+ message,
189
+ {
190
+ shouldProcessHistoryMsg,
191
+ placeholderResendCache,
192
+ ev,
193
+ creds,
194
+ signalRepository,
195
+ keyStore,
196
+ logger,
197
+ options,
198
+ getMessage
199
+ }
200
+ ) => {
201
+ const meId = creds.me.id
202
+ const { accountSettings } = creds
203
+ const chat = { id: (0, WABinary_1.jidNormalizedUser)((0, exports.getChatId)(message.key)) }
204
+ const isRealMsg = (0, exports.isRealMessage)(message)
205
+ if (isRealMsg) {
206
+ chat.messages = [{ message }]
207
+ chat.conversationTimestamp = (0, generics_1.toNumber)(message.messageTimestamp)
208
+ // only increment unread count if not CIPHERTEXT and from another person
209
+ if ((0, exports.shouldIncrementChatUnread)(message)) {
210
+ chat.unreadCount = (chat.unreadCount || 0) + 1
211
+ }
212
+ }
213
+ if (message.statusPsa) {
214
+ ev.emit('status.psa', {
215
+ key: message.key,
216
+ psa: message.statusPsa,
217
+ chatId: chat.id
218
+ })
219
+ }
220
+ if (message.quarantinedMessage) {
221
+ ev.emit('message.quarantined', {
222
+ key: message.key,
223
+ quarantineInfo: message.quarantinedMessage,
224
+ chatId: chat.id
225
+ })
226
+ }
227
+ if (message.interactiveMessageAdditionalMetadata?.isGalaxyFlowCompleted) {
228
+ ev.emit('galaxy.flow.completed', {
229
+ key: message.key,
230
+ chatId: chat.id
231
+ })
232
+ }
233
+ if (message.ephemeralExpirationTimestamp) {
234
+ Object.assign(chat, {
235
+ ephemeralExpirationTimestamp: (0, generics_1.toNumber)(message.ephemeralExpirationTimestamp)
236
+ })
237
+ }
238
+ const content = (0, messages_1.normalizeMessageContent)(message.message)
239
+ // unarchive chat if it's a real message, or someone reacted to our message
240
+ // and we've the unarchive chats setting on
241
+ if ((isRealMsg || content?.reactionMessage?.key?.fromMe) && accountSettings?.unarchiveChats) {
242
+ chat.archived = false
243
+ chat.readOnly = false
244
+ }
245
+ const protocolMsg = content?.protocolMessage
246
+ if (protocolMsg) {
247
+ switch (protocolMsg.type) {
248
+ case index_js_1.proto.Message.ProtocolMessage.Type.HISTORY_SYNC_NOTIFICATION:
249
+ const histNotification = protocolMsg.historySyncNotification
250
+ const process = shouldProcessHistoryMsg
251
+ const isLatest = !creds.processedHistoryMessages?.length
252
+ logger?.info(
253
+ {
254
+ histNotification,
255
+ process,
256
+ id: message.key.id,
257
+ isLatest
258
+ },
259
+ 'got history notification'
260
+ )
261
+ if (process) {
262
+ // TODO: investigate
263
+ if (histNotification.syncType !== index_js_1.proto.HistorySync.HistorySyncType.ON_DEMAND) {
264
+ ev.emit('creds.update', {
265
+ processedHistoryMessages: [
266
+ ...(creds.processedHistoryMessages || []),
267
+ { key: message.key, messageTimestamp: message.messageTimestamp }
268
+ ]
269
+ })
270
+ }
271
+ const data = await (0, history_1.downloadAndProcessHistorySyncNotification)(histNotification, options, logger)
272
+ if (data.lidPnMappings?.length) {
273
+ logger?.debug({ count: data.lidPnMappings.length }, 'processing LID-PN mappings from history sync')
274
+ await signalRepository.lidMapping
275
+ .storeLIDPNMappings(data.lidPnMappings)
276
+ .catch(err => logger?.warn({ err }, 'failed to store LID-PN mappings from history sync'))
277
+ }
278
+ await storeTcTokensFromHistorySync(data.chats, signalRepository, keyStore, logger)
279
+ ev.emit('messaging-history.set', {
280
+ ...data,
281
+ isLatest:
282
+ histNotification.syncType !== index_js_1.proto.HistorySync.HistorySyncType.ON_DEMAND
283
+ ? isLatest
284
+ : undefined,
285
+ peerDataRequestSessionId: histNotification.peerDataRequestSessionId
286
+ })
287
+ }
288
+ break
289
+ case index_js_1.proto.Message.ProtocolMessage.Type.APP_STATE_SYNC_KEY_SHARE:
290
+ const keys = protocolMsg.appStateSyncKeyShare.keys
291
+ if (keys?.length) {
292
+ let newAppStateSyncKeyId = ''
293
+ await keyStore.transaction(async () => {
294
+ const newKeys = []
295
+ for (const { keyData, keyId } of keys) {
296
+ const strKeyId = Buffer.from(keyId.keyId).toString('base64')
297
+ newKeys.push(strKeyId)
298
+ await keyStore.set({ 'app-state-sync-key': { [strKeyId]: keyData } })
299
+ newAppStateSyncKeyId = strKeyId
300
+ }
301
+ logger?.info({ newAppStateSyncKeyId, newKeys }, 'injecting new app state sync keys')
302
+ }, meId)
303
+ ev.emit('creds.update', { myAppStateKeyId: newAppStateSyncKeyId })
304
+ } else {
305
+ logger?.info({ protocolMsg }, 'recv app state sync with 0 keys')
306
+ }
307
+ break
308
+ case index_js_1.proto.Message.ProtocolMessage.Type.REVOKE:
309
+ ev.emit('messages.update', [
310
+ {
311
+ key: {
312
+ ...message.key,
313
+ id: protocolMsg.key.id
314
+ },
315
+ update: { message: null, messageStubType: Types_1.WAMessageStubType.REVOKE, key: message.key }
316
+ }
317
+ ])
318
+ break
319
+ case index_js_1.proto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING:
320
+ Object.assign(chat, {
321
+ ephemeralSettingTimestamp: (0, generics_1.toNumber)(message.messageTimestamp),
322
+ ephemeralExpiration: protocolMsg.ephemeralExpiration || null
323
+ })
324
+ break
325
+ case index_js_1.proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_RESPONSE_MESSAGE:
326
+ const response = protocolMsg.peerDataOperationRequestResponseMessage
327
+ if (response) {
328
+ // TODO: IMPLEMENT HISTORY SYNC ETC (sticker uploads etc.).
329
+ const peerDataOperationResult = response.peerDataOperationResult || []
330
+ for (const result of peerDataOperationResult) {
331
+ const retryResponse = result?.placeholderMessageResendResponse
332
+ //eslint-disable-next-line max-depth
333
+ if (!retryResponse?.webMessageInfoBytes) {
334
+ continue
335
+ }
336
+ //eslint-disable-next-line max-depth
337
+ try {
338
+ const webMessageInfo = index_js_1.proto.WebMessageInfo.decode(retryResponse.webMessageInfoBytes)
339
+ const msgId = webMessageInfo.key?.id
340
+ // Retrieve cached original message data (preserves LID details,
341
+ // timestamps, etc. that the phone may omit in its PDO response)
342
+ const cachedData = msgId ? await placeholderResendCache?.get(msgId) : undefined
343
+ //eslint-disable-next-line max-depth
344
+ if (msgId) {
345
+ await placeholderResendCache?.del(msgId)
346
+ }
347
+ let finalMsg
348
+ //eslint-disable-next-line max-depth
349
+ if (cachedData && typeof cachedData === 'object') {
350
+ // Apply decoded message content onto cached metadata (preserves LID etc.)
351
+ cachedData.message = webMessageInfo.message
352
+ //eslint-disable-next-line max-depth
353
+ if (webMessageInfo.messageTimestamp) {
354
+ cachedData.messageTimestamp = webMessageInfo.messageTimestamp
355
+ }
356
+ finalMsg = cachedData
357
+ } else {
358
+ finalMsg = webMessageInfo
359
+ }
360
+ logger?.debug({ msgId, requestId: response.stanzaId }, 'received placeholder resend')
361
+ ev.emit('messages.upsert', {
362
+ messages: [finalMsg],
363
+ type: 'notify',
364
+ requestId: response.stanzaId
365
+ })
366
+ } catch (err) {
367
+ logger?.warn({ err, stanzaId: response.stanzaId }, 'failed to decode placeholder resend response')
368
+ }
369
+ }
370
+ }
371
+ break
372
+ case index_js_1.proto.Message.ProtocolMessage.Type.MESSAGE_EDIT:
373
+ ev.emit('messages.update', [
374
+ {
375
+ // flip the sender / fromMe properties because they're in the perspective of the sender
376
+ key: { ...message.key, id: protocolMsg.key?.id },
377
+ update: {
378
+ message: {
379
+ editedMessage: {
380
+ message: protocolMsg.editedMessage
381
+ }
382
+ },
383
+ messageTimestamp: protocolMsg.timestampMs
384
+ ? Math.floor((0, generics_1.toNumber)(protocolMsg.timestampMs) / 1000)
385
+ : message.messageTimestamp
386
+ }
387
+ }
388
+ ])
389
+ break
390
+ case index_js_1.proto.Message.ProtocolMessage.Type.GROUP_MEMBER_LABEL_CHANGE:
391
+ const labelAssociationMsg = protocolMsg.memberLabel
392
+ if (labelAssociationMsg?.label) {
393
+ ev.emit('group.member-tag.update', {
394
+ groupId: chat.id,
395
+ label: labelAssociationMsg.label,
396
+ participant: message.key.participant,
397
+ participantAlt: message.key.participantAlt,
398
+ messageTimestamp: Number(message.messageTimestamp)
399
+ })
400
+ }
401
+ break
402
+ case index_js_1.proto.Message.ProtocolMessage.Type.BOT_FEEDBACK_MESSAGE:
403
+ if (protocolMsg.botFeedbackMessage) {
404
+ ev.emit('bot.feedback', {
405
+ key: message.key,
406
+ botFeedback: protocolMsg.botFeedbackMessage,
407
+ targetKey: protocolMsg.key
408
+ })
409
+ }
410
+ break
411
+ case index_js_1.proto.Message.ProtocolMessage.Type.CLOUD_API_THREAD_CONTROL_NOTIFICATION:
412
+ if (protocolMsg.cloudAPIThreadControlNotification) {
413
+ ev.emit('cloud.thread.control', {
414
+ key: message.key,
415
+ notification: protocolMsg.cloudAPIThreadControlNotification,
416
+ chatId: chat.id
417
+ })
418
+ }
419
+ break
420
+ case index_js_1.proto.Message.ProtocolMessage.Type.CHAT_THEME_SETTING:
421
+ if (protocolMsg.chatThemeSetting) {
422
+ ev.emit('chats.update', [
423
+ {
424
+ id: chat.id,
425
+ chatThemeSetting: protocolMsg.chatThemeSetting
426
+ }
427
+ ])
428
+ }
429
+ break
430
+ case index_js_1.proto.Message.ProtocolMessage.Type.STOP_GENERATION_MESSAGE:
431
+ ev.emit('bot.stop-generation', {
432
+ key: message.key,
433
+ targetKey: protocolMsg.key,
434
+ chatId: chat.id
435
+ })
436
+ break
437
+ case index_js_1.proto.Message.ProtocolMessage.Type.MEDIA_NOTIFY_MESSAGE:
438
+ if (protocolMsg.mediaNotifyMessage) {
439
+ ev.emit('media.notify', {
440
+ key: message.key,
441
+ mediaNotify: protocolMsg.mediaNotifyMessage
442
+ })
443
+ }
444
+ break
445
+ case index_js_1.proto.Message.ProtocolMessage.Type.REQUEST_WELCOME_MESSAGE:
446
+ ev.emit('bot.welcome-request', {
447
+ key: message.key,
448
+ chatId: chat.id,
449
+ timestamp: message.messageTimestamp
450
+ })
451
+ break
452
+ case index_js_1.proto.Message.ProtocolMessage.Type.BOT_MEMU_ONBOARDING_MESSAGE:
453
+ ev.emit('bot.memu-onboarding', {
454
+ key: message.key,
455
+ chatId: chat.id
456
+ })
457
+ break
458
+ case index_js_1.proto.Message.ProtocolMessage.Type.STATUS_MENTION_MESSAGE:
459
+ if (protocolMsg.statusMentionMessage) {
460
+ ev.emit('status.mention', {
461
+ key: message.key,
462
+ statusMention: protocolMsg.statusMentionMessage,
463
+ chatId: chat.id
464
+ })
465
+ }
466
+ break
467
+ case index_js_1.proto.Message.ProtocolMessage.Type.AI_PSI_METADATA:
468
+ if (protocolMsg.aiPsiMetadata) {
469
+ ev.emit('bot.psi-metadata', {
470
+ key: message.key,
471
+ psiMetadata: protocolMsg.aiPsiMetadata,
472
+ chatId: chat.id
473
+ })
474
+ }
475
+ break
476
+ case index_js_1.proto.Message.ProtocolMessage.Type.AI_QUERY_FANOUT:
477
+ if (protocolMsg.aiQueryFanout) {
478
+ ev.emit('bot.query-fanout', {
479
+ key: message.key,
480
+ queryFanout: protocolMsg.aiQueryFanout,
481
+ chatId: chat.id
482
+ })
483
+ }
484
+ break
485
+ case index_js_1.proto.Message.ProtocolMessage.Type.AI_MEDIA_COLLECTION_MESSAGE:
486
+ if (protocolMsg.aiMediaCollectionMessage) {
487
+ ev.emit('bot.media-collection', {
488
+ key: message.key,
489
+ collection: protocolMsg.aiMediaCollectionMessage,
490
+ chatId: chat.id
491
+ })
492
+ }
493
+ break
494
+ case index_js_1.proto.Message.ProtocolMessage.Type.REMINDER_MESSAGE:
495
+ ev.emit('reminder.update', {
496
+ key: message.key,
497
+ chatId: chat.id,
498
+ timestamp: message.messageTimestamp
499
+ })
500
+ break
501
+ case index_js_1.proto.Message.ProtocolMessage.Type.MESSAGE_UNSCHEDULE:
502
+ if (protocolMsg.key) {
503
+ ev.emit('messages.update', [
504
+ {
505
+ key: { ...message.key, id: protocolMsg.key.id },
506
+ update: { scheduledMessageMetadata: null }
507
+ }
508
+ ])
509
+ }
510
+ break
511
+ case index_js_1.proto.Message.ProtocolMessage.Type.LID_MIGRATION_MAPPING_SYNC:
512
+ const encodedPayload = protocolMsg.lidMigrationMappingSyncMessage?.encodedMappingPayload
513
+ const { pnToLidMappings, chatDbMigrationTimestamp } =
514
+ index_js_1.proto.LIDMigrationMappingSyncPayload.decode(encodedPayload)
515
+ logger?.debug({ pnToLidMappings, chatDbMigrationTimestamp }, 'got lid mappings and chat db migration timestamp')
516
+ const pairs = []
517
+ for (const { pn, latestLid, assignedLid } of pnToLidMappings) {
518
+ const lid = latestLid || assignedLid
519
+ pairs.push({ lid: `${lid}@lid`, pn: `${pn}@s.whatsapp.net` })
520
+ }
521
+ await signalRepository.lidMapping.storeLIDPNMappings(pairs)
522
+ if (pairs.length) {
523
+ for (const { pn, lid } of pairs) {
524
+ await signalRepository.migrateSession(pn, lid)
525
+ }
526
+ }
527
+ }
528
+ } else if (content?.reactionMessage) {
529
+ const reaction = {
530
+ ...content.reactionMessage,
531
+ key: message.key
532
+ }
533
+ ev.emit('messages.reaction', [
534
+ {
535
+ reaction,
536
+ key: content.reactionMessage?.key
537
+ }
538
+ ])
539
+ } else if (content?.keepInChatMessage) {
540
+ const kic = content.keepInChatMessage
541
+ if (kic.key) {
542
+ ev.emit('messages.update', [
543
+ {
544
+ key: kic.key,
545
+ update: { keepInChat: { keepType: kic.keepType, serverTimestamp: message.messageTimestamp, key: kic.key } }
546
+ }
547
+ ])
548
+ }
549
+ } else if (content?.encReactionMessage) {
550
+ ev.emit('messages.update', [
551
+ {
552
+ key: content.encReactionMessage.targetMessageKey,
553
+ update: { encReactionMessage: content.encReactionMessage }
554
+ }
555
+ ])
556
+ } else if (content?.commentMessage) {
557
+ if (content.commentMessage.targetMessageKey) {
558
+ ev.emit('message.comment', {
559
+ comment: content.commentMessage,
560
+ commentKey: message.key,
561
+ targetKey: content.commentMessage.targetMessageKey
562
+ })
563
+ }
564
+ } else if (content?.encCommentMessage) {
565
+ ev.emit('message.comment', {
566
+ comment: content.encCommentMessage,
567
+ commentKey: message.key,
568
+ targetKey: content.encCommentMessage.targetMessageKey,
569
+ encrypted: true
570
+ })
571
+ } else if (content?.bcallMessage) {
572
+ ev.emit('call', [
573
+ {
574
+ id: content.bcallMessage.sessionId || message.key.id,
575
+ from: message.key.participant || message.key.remoteJid,
576
+ chatId: chat.id,
577
+ isVideo: content.bcallMessage.mediaType === index_js_1.proto.Message.BCallMessage.MediaType.VIDEO,
578
+ isBroadcast: true,
579
+ caption: content.bcallMessage.caption
580
+ }
581
+ ])
582
+ } else if (content?.pollAddOptionMessage) {
583
+ const pao = content.pollAddOptionMessage
584
+ if (pao.pollCreationMessageKey) {
585
+ ev.emit('poll.add-option', {
586
+ pollKey: pao.pollCreationMessageKey,
587
+ addedOption: pao.addOption,
588
+ addedBy: message.key.participant || message.key.remoteJid,
589
+ messageKey: message.key
590
+ })
591
+ }
592
+ } else if (content?.scheduledCallCreationMessage) {
593
+ ev.emit('call.scheduled', {
594
+ messageKey: message.key,
595
+ scheduledCall: content.scheduledCallCreationMessage,
596
+ chatId: chat.id
597
+ })
598
+ } else if (content?.scheduledCallEditMessage) {
599
+ ev.emit('call.schedule-cancelled', {
600
+ messageKey: message.key,
601
+ editedCallKey: content.scheduledCallEditMessage.key,
602
+ chatId: chat.id
603
+ })
604
+ } else if (content?.splitPaymentMessage) {
605
+ ev.emit('payment.split', {
606
+ messageKey: message.key,
607
+ splitPayment: content.splitPaymentMessage,
608
+ chatId: chat.id
609
+ })
610
+ } else if (content?.p2PPaymentReminderNotification) {
611
+ ev.emit('payment.reminder', {
612
+ messageKey: message.key,
613
+ reminder: content.p2PPaymentReminderNotification,
614
+ chatId: chat.id
615
+ })
616
+ } else if (content?.encEventResponseMessage) {
617
+ const encEventResponse = content.encEventResponseMessage
618
+ const creationMsgKey = encEventResponse.eventCreationMessageKey
619
+ // we need to fetch the event creation message to get the event enc key
620
+ const eventMsg = await getMessage(creationMsgKey)
621
+ if (eventMsg) {
622
+ try {
623
+ const meIdNormalised = (0, WABinary_1.jidNormalizedUser)(meId)
624
+ // all jids need to be PN
625
+ const eventCreatorKey = creationMsgKey.participant || creationMsgKey.remoteJid
626
+ const eventCreatorPn = (0, WABinary_1.isLidUser)(eventCreatorKey)
627
+ ? await signalRepository.lidMapping.getPNForLID(eventCreatorKey)
628
+ : eventCreatorKey
629
+ const eventCreatorJid = (0, generics_1.getKeyAuthor)(
630
+ { remoteJid: (0, WABinary_1.jidNormalizedUser)(eventCreatorPn), fromMe: meIdNormalised === eventCreatorPn },
631
+ meIdNormalised
632
+ )
633
+ const responderJid = (0, generics_1.getKeyAuthor)(message.key, meIdNormalised)
634
+ const eventEncKey = eventMsg?.messageContextInfo?.messageSecret
635
+ if (!eventEncKey) {
636
+ logger?.warn({ creationMsgKey }, 'event response: missing messageSecret for decryption')
637
+ } else {
638
+ const responseMsg = decryptEventResponse(encEventResponse, {
639
+ eventEncKey,
640
+ eventCreatorJid,
641
+ eventMsgId: creationMsgKey.id,
642
+ responderJid
643
+ })
644
+ const eventResponse = {
645
+ eventResponseMessageKey: message.key,
646
+ senderTimestampMs: responseMsg.timestampMs,
647
+ response: responseMsg
648
+ }
649
+ ev.emit('messages.update', [
650
+ {
651
+ key: creationMsgKey,
652
+ update: {
653
+ eventResponses: [eventResponse]
654
+ }
655
+ }
656
+ ])
657
+ }
658
+ } catch (err) {
659
+ logger?.warn({ err, creationMsgKey }, 'failed to decrypt event response')
660
+ }
661
+ } else {
662
+ logger?.warn({ creationMsgKey }, 'event creation message not found, cannot decrypt response')
663
+ }
664
+ } else if (message.messageStubType) {
665
+ const jid = message.key?.remoteJid
666
+ //let actor = whatsappID (message.participant)
667
+ let participants
668
+ const emitParticipantsUpdate = action =>
669
+ ev.emit('group-participants.update', {
670
+ id: jid,
671
+ author: message.key.participant,
672
+ authorPn: message.key.participantAlt,
673
+ authorUsername: message.key.participantUsername,
674
+ participants,
675
+ action
676
+ })
677
+ const emitGroupUpdate = update => {
678
+ ev.emit('groups.update', [
679
+ {
680
+ id: jid,
681
+ ...update,
682
+ author: message.key.participant ?? undefined,
683
+ authorPn: message.key.participantAlt,
684
+ authorUsername: message.key.participantUsername
685
+ }
686
+ ])
687
+ }
688
+ const emitGroupRequestJoin = (participant, action, method) => {
689
+ ev.emit('group.join-request', {
690
+ id: jid,
691
+ author: message.key.participant,
692
+ authorPn: message.key.participantAlt,
693
+ authorUsername: message.key.participantUsername,
694
+ participant: participant.lid,
695
+ participantPn: participant.pn,
696
+ action,
697
+ method: method
698
+ })
699
+ }
700
+ const participantsIncludesMe = () =>
701
+ participants.find(jid => (0, WABinary_1.areJidsSameUser)(meId, jid.phoneNumber)) // ADD SUPPORT FOR LID
702
+ switch (message.messageStubType) {
703
+ case Types_1.WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER:
704
+ participants = message.messageStubParameters.map(a => JSON.parse(a)) || []
705
+ emitParticipantsUpdate('modify')
706
+ break
707
+ case Types_1.WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
708
+ case Types_1.WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
709
+ participants = message.messageStubParameters.map(a => JSON.parse(a)) || []
710
+ emitParticipantsUpdate('remove')
711
+ // mark the chat read only if you left the group
712
+ if (participantsIncludesMe()) {
713
+ chat.readOnly = true
714
+ }
715
+ break
716
+ case Types_1.WAMessageStubType.GROUP_PARTICIPANT_ADD:
717
+ case Types_1.WAMessageStubType.GROUP_PARTICIPANT_INVITE:
718
+ case Types_1.WAMessageStubType.GROUP_PARTICIPANT_ADD_REQUEST_JOIN:
719
+ participants = message.messageStubParameters.map(a => JSON.parse(a)) || []
720
+ if (participantsIncludesMe()) {
721
+ chat.readOnly = false
722
+ }
723
+ emitParticipantsUpdate('add')
724
+ break
725
+ case Types_1.WAMessageStubType.GROUP_PARTICIPANT_DEMOTE:
726
+ participants = message.messageStubParameters.map(a => JSON.parse(a)) || []
727
+ emitParticipantsUpdate('demote')
728
+ break
729
+ case Types_1.WAMessageStubType.GROUP_PARTICIPANT_PROMOTE:
730
+ participants = message.messageStubParameters.map(a => JSON.parse(a)) || []
731
+ emitParticipantsUpdate('promote')
732
+ break
733
+ case Types_1.WAMessageStubType.GROUP_CHANGE_ANNOUNCE:
734
+ const announceValue = message.messageStubParameters?.[0]
735
+ emitGroupUpdate({ announce: announceValue === 'true' || announceValue === 'on' })
736
+ break
737
+ case Types_1.WAMessageStubType.GROUP_CHANGE_RESTRICT:
738
+ const restrictValue = message.messageStubParameters?.[0]
739
+ emitGroupUpdate({ restrict: restrictValue === 'true' || restrictValue === 'on' })
740
+ break
741
+ case Types_1.WAMessageStubType.GROUP_CHANGE_SUBJECT:
742
+ const name = message.messageStubParameters?.[0]
743
+ chat.name = name
744
+ emitGroupUpdate({ subject: name })
745
+ break
746
+ case Types_1.WAMessageStubType.GROUP_CHANGE_DESCRIPTION:
747
+ const description = message.messageStubParameters?.[0]
748
+ chat.description = description
749
+ emitGroupUpdate({ desc: description })
750
+ break
751
+ case Types_1.WAMessageStubType.GROUP_CHANGE_INVITE_LINK:
752
+ const code = message.messageStubParameters?.[0]
753
+ emitGroupUpdate({ inviteCode: code })
754
+ break
755
+ case Types_1.WAMessageStubType.GROUP_MEMBER_ADD_MODE:
756
+ const memberAddValue = message.messageStubParameters?.[0]
757
+ emitGroupUpdate({ memberAddMode: memberAddValue === 'all_member_add' })
758
+ break
759
+ case Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE:
760
+ const approvalMode = message.messageStubParameters?.[0]
761
+ emitGroupUpdate({ joinApprovalMode: approvalMode === 'on' })
762
+ break
763
+ case Types_1.WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD: // TODO: Add other events
764
+ const participant = JSON.parse(message.messageStubParameters?.[0])
765
+ const action = message.messageStubParameters?.[1]
766
+ const method = message.messageStubParameters?.[2]
767
+ emitGroupRequestJoin(participant, action, method)
768
+ break
769
+ case Types_1.WAMessageStubType.GROUP_CREATE:
770
+ emitGroupUpdate({ subject: message.messageStubParameters?.[0] })
771
+ break
772
+ case Types_1.WAMessageStubType.GROUP_CHANGE_ICON:
773
+ emitGroupUpdate({ pictureId: message.messageStubParameters?.[0] })
774
+ break
775
+ case Types_1.WAMessageStubType.GROUP_DELETE:
776
+ emitGroupUpdate({ readOnly: true, deleted: true })
777
+ break
778
+ case Types_1.WAMessageStubType.GROUP_CREATING:
779
+ emitGroupUpdate({ subject: message.messageStubParameters?.[0], creating: true })
780
+ break
781
+ case Types_1.WAMessageStubType.GROUP_CREATE_FAILED:
782
+ emitGroupUpdate({ createFailed: true })
783
+ break
784
+ case Types_1.WAMessageStubType.GROUP_BOUNCED:
785
+ emitGroupUpdate({ bounced: true })
786
+ break
787
+ case Types_1.WAMessageStubType.CHANGE_EPHEMERAL_SETTING:
788
+ const ephValue = message.messageStubParameters?.[0]
789
+ emitGroupUpdate({ ephemeralDuration: ephValue ? +ephValue : 0 })
790
+ break
791
+ case Types_1.WAMessageStubType.DISAPPEARING_MODE:
792
+ const disappearingValue = message.messageStubParameters?.[0]
793
+ emitGroupUpdate({ ephemeralDuration: disappearingValue ? +disappearingValue : 0 })
794
+ break
795
+ case Types_1.WAMessageStubType.ADMIN_REVOKE:
796
+ emitGroupUpdate({ adminRevoked: true, revokedBy: message.messageStubParameters?.[0] })
797
+ break
798
+ case Types_1.WAMessageStubType.BLOCK_CONTACT:
799
+ ev.emit('contacts.update', [{ id: jid, isBlocked: true }])
800
+ break
801
+ case Types_1.WAMessageStubType.CHANGE_USERNAME:
802
+ ev.emit('contacts.update', [
803
+ { id: message.key.participant || jid, username: message.messageStubParameters?.[0] }
804
+ ])
805
+ break
806
+ case Types_1.WAMessageStubType.GROUP_PARTICIPANT_ACCEPT:
807
+ participants =
808
+ message.messageStubParameters?.map(a => {
809
+ try {
810
+ return JSON.parse(a)
811
+ } catch {
812
+ return a
813
+ }
814
+ }) || []
815
+ emitParticipantsUpdate('accept')
816
+ break
817
+ case Types_1.WAMessageStubType.GROUP_PARTICIPANT_LINKED_GROUP_JOIN:
818
+ participants =
819
+ message.messageStubParameters?.map(a => {
820
+ try {
821
+ return JSON.parse(a)
822
+ } catch {
823
+ return a
824
+ }
825
+ }) || []
826
+ emitParticipantsUpdate('linked-group-join')
827
+ break
828
+ case Types_1.WAMessageStubType.EPHEMERAL_KEEP_IN_CHAT:
829
+ ev.emit('messages.update', [{ key: message.key, update: { keepInChat: true } }])
830
+ break
831
+ case Types_1.WAMessageStubType.PINNED_MESSAGE_IN_CHAT:
832
+ ev.emit('messages.update', [
833
+ {
834
+ key: message.key,
835
+ update: {
836
+ pinInChat: {
837
+ pinned: true,
838
+ pinnedMessageKey: message.messageStubParameters?.[0]
839
+ ? { id: message.messageStubParameters[0] }
840
+ : undefined,
841
+ senderTimestampMs: message.messageTimestamp
842
+ ? (0, generics_1.toNumber)(message.messageTimestamp) * 1000
843
+ : undefined
844
+ }
845
+ }
846
+ }
847
+ ])
848
+ break
849
+ case Types_1.WAMessageStubType.CHAT_PSA:
850
+ ev.emit('chats.update', [{ id: jid, psa: { urlParams: message.messageStubParameters } }])
851
+ break
852
+ case Types_1.WAMessageStubType.CHAT_POLL_CREATION_MESSAGE:
853
+ // poll was created, no special action needed beyond message processing
854
+ break
855
+ case Types_1.WAMessageStubType.BIZ_CHAT_ASSIGNMENT:
856
+ ev.emit('chats.update', [
857
+ {
858
+ id: jid,
859
+ bizAssignment: {
860
+ assigned: true,
861
+ assignee: message.messageStubParameters?.[0],
862
+ agent: message.messageStubParameters?.[1]
863
+ }
864
+ }
865
+ ])
866
+ break
867
+ case Types_1.WAMessageStubType.BIZ_CHAT_ASSIGNMENT_UNASSIGN:
868
+ ev.emit('chats.update', [{ id: jid, bizAssignment: { assigned: false } }])
869
+ break
870
+ case Types_1.WAMessageStubType.SILENCED_UNKNOWN_CALLER_AUDIO:
871
+ case Types_1.WAMessageStubType.SILENCED_UNKNOWN_CALLER_VIDEO:
872
+ ev.emit('call', [
873
+ {
874
+ id: message.messageStubParameters?.[0] || message.key.id,
875
+ from: jid,
876
+ isVideo: message.messageStubType === Types_1.WAMessageStubType.SILENCED_UNKNOWN_CALLER_VIDEO,
877
+ status: 'silenced',
878
+ isUnknown: true,
879
+ timestamp: (0, generics_1.toNumber)(message.messageTimestamp)
880
+ }
881
+ ])
882
+ break
883
+ case Types_1.WAMessageStubType.SCHEDULED_CALL_START_MESSAGE:
884
+ ev.emit('call', [
885
+ {
886
+ id: message.messageStubParameters?.[0] || message.key.id,
887
+ from: message.key.participant || jid,
888
+ status: 'scheduled-start',
889
+ timestamp: (0, generics_1.toNumber)(message.messageTimestamp)
890
+ }
891
+ ])
892
+ break
893
+ case Types_1.WAMessageStubType.SCHEDULED_CALL_CANCEL:
894
+ ev.emit('call', [
895
+ {
896
+ id: message.messageStubParameters?.[0] || message.key.id,
897
+ from: message.key.participant || jid,
898
+ status: 'schedule-cancelled',
899
+ timestamp: (0, generics_1.toNumber)(message.messageTimestamp)
900
+ }
901
+ ])
902
+ break
903
+ case Types_1.WAMessageStubType.COMMUNITY_CREATE:
904
+ emitGroupUpdate({ isCommunity: true, subject: message.messageStubParameters?.[0] })
905
+ break
906
+ case Types_1.WAMessageStubType.COMMUNITY_LINK_PARENT_GROUP:
907
+ case Types_1.WAMessageStubType.COMMUNITY_LINK_PARENT_GROUP_RICH:
908
+ emitGroupUpdate({ linkedParent: message.messageStubParameters?.[0] })
909
+ break
910
+ case Types_1.WAMessageStubType.COMMUNITY_LINK_SUB_GROUP:
911
+ case Types_1.WAMessageStubType.COMMUNITY_LINK_SIBLING_GROUP:
912
+ emitGroupUpdate({ linkedSubGroup: message.messageStubParameters?.[0] })
913
+ break
914
+ case Types_1.WAMessageStubType.COMMUNITY_UNLINK_PARENT_GROUP:
915
+ emitGroupUpdate({ linkedParent: undefined })
916
+ break
917
+ case Types_1.WAMessageStubType.COMMUNITY_UNLINK_SUB_GROUP:
918
+ case Types_1.WAMessageStubType.COMMUNITY_UNLINK_SIBLING_GROUP:
919
+ emitGroupUpdate({ unlinkedSubGroup: message.messageStubParameters?.[0] })
920
+ break
921
+ case Types_1.WAMessageStubType.COMMUNITY_PARTICIPANT_PROMOTE:
922
+ participants =
923
+ message.messageStubParameters?.map(a => {
924
+ try {
925
+ return JSON.parse(a)
926
+ } catch {
927
+ return a
928
+ }
929
+ }) || []
930
+ emitParticipantsUpdate('promote')
931
+ break
932
+ case Types_1.WAMessageStubType.COMMUNITY_PARTICIPANT_DEMOTE:
933
+ participants =
934
+ message.messageStubParameters?.map(a => {
935
+ try {
936
+ return JSON.parse(a)
937
+ } catch {
938
+ return a
939
+ }
940
+ }) || []
941
+ emitParticipantsUpdate('demote')
942
+ break
943
+ case Types_1.WAMessageStubType.COMMUNITY_PARENT_GROUP_DELETED:
944
+ emitGroupUpdate({ parentDeleted: true, readOnly: true })
945
+ break
946
+ case Types_1.WAMessageStubType.COMMUNITY_PARENT_GROUP_SUBJECT_CHANGED:
947
+ emitGroupUpdate({ parentSubject: message.messageStubParameters?.[0] })
948
+ break
949
+ case Types_1.WAMessageStubType.COMMUNITY_LINK_PARENT_GROUP_MEMBERSHIP_APPROVAL:
950
+ emitGroupUpdate({ linkedParentMembershipApproval: message.messageStubParameters?.[0] === 'true' })
951
+ break
952
+ case Types_1.WAMessageStubType.COMMUNITY_INVITE_RICH:
953
+ case Types_1.WAMessageStubType.COMMUNITY_INVITE_AUTO_ADD_RICH:
954
+ participants =
955
+ message.messageStubParameters?.map(a => {
956
+ try {
957
+ return JSON.parse(a)
958
+ } catch {
959
+ return a
960
+ }
961
+ }) || []
962
+ emitParticipantsUpdate('add')
963
+ break
964
+ case Types_1.WAMessageStubType.COMMUNITY_PARTICIPANT_ADD_RICH:
965
+ participants =
966
+ message.messageStubParameters?.map(a => {
967
+ try {
968
+ return JSON.parse(a)
969
+ } catch {
970
+ return a
971
+ }
972
+ }) || []
973
+ emitParticipantsUpdate('add')
974
+ break
975
+ case Types_1.WAMessageStubType.COMMUNITY_CHANGE_DESCRIPTION:
976
+ const communityDesc = message.messageStubParameters?.[0]
977
+ emitGroupUpdate({ desc: communityDesc })
978
+ break
979
+ case Types_1.WAMessageStubType.COMMUNITY_ALLOW_MEMBER_ADDED_GROUPS:
980
+ emitGroupUpdate({ communityMemberAddGroupMode: message.messageStubParameters?.[0] })
981
+ break
982
+ case Types_1.WAMessageStubType.EMPTY_SUBGROUP_CREATE:
983
+ emitGroupUpdate({ subject: message.messageStubParameters?.[0], isEmpty: true })
984
+ break
985
+ case Types_1.WAMessageStubType.COMMUNITY_DEACTIVATE_SIBLING_GROUP:
986
+ emitGroupUpdate({ deactivated: true, linkedSibling: message.messageStubParameters?.[0] })
987
+ break
988
+ case Types_1.WAMessageStubType.COMMUNITY_OWNER_UPDATED:
989
+ emitGroupUpdate({ owner: message.messageStubParameters?.[0] })
990
+ break
991
+ case Types_1.WAMessageStubType.COMMUNITY_SUB_GROUP_VISIBILITY_HIDDEN:
992
+ emitGroupUpdate({ hidden: true })
993
+ break
994
+ }
995
+ } /* else if(content?.pollUpdateMessage) {
996
+ const creationMsgKey = content.pollUpdateMessage.pollCreationMessageKey!
997
+ // we need to fetch the poll creation message to get the poll enc key
998
+ // TODO: make standalone, remove getMessage reference
999
+ // TODO: Remove entirely
1000
+ const pollMsg = await getMessage(creationMsgKey)
1001
+ if(pollMsg) {
1002
+ const meIdNormalised = jidNormalizedUser(meId)
1003
+ const pollCreatorJid = getKeyAuthor(creationMsgKey, meIdNormalised)
1004
+ const voterJid = getKeyAuthor(message.key, meIdNormalised)
1005
+ const pollEncKey = pollMsg.messageContextInfo?.messageSecret!
1006
+
1007
+ try {
1008
+ const voteMsg = decryptPollVote(
1009
+ content.pollUpdateMessage.vote!,
1010
+ {
1011
+ pollEncKey,
1012
+ pollCreatorJid,
1013
+ pollMsgId: creationMsgKey.id!,
1014
+ voterJid,
1015
+ }
1016
+ )
1017
+ ev.emit('messages.update', [
1018
+ {
1019
+ key: creationMsgKey,
1020
+ update: {
1021
+ pollUpdates: [
1022
+ {
1023
+ pollUpdateMessageKey: message.key,
1024
+ vote: voteMsg,
1025
+ senderTimestampMs: (content.pollUpdateMessage.senderTimestampMs! as Long).toNumber(),
1026
+ }
1027
+ ]
1028
+ }
1029
+ }
1030
+ ])
1031
+ } catch(err) {
1032
+ logger?.warn(
1033
+ { err, creationMsgKey },
1034
+ 'failed to decrypt poll vote'
1035
+ )
1036
+ }
1037
+ } else {
1038
+ logger?.warn(
1039
+ { creationMsgKey },
1040
+ 'poll creation message not found, cannot decrypt update'
1041
+ )
1042
+ }
1043
+ } */
1044
+ if (Object.keys(chat).length > 1) {
1045
+ ev.emit('chats.update', [chat])
1046
+ }
1047
+ }
1048
+ exports.default = processMessage