@badzz88/baileys 8.4.7 → 8.4.9

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