@hansaka02/baileys 7.3.4 → 7.3.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 (50) hide show
  1. package/README.md +203 -247
  2. package/lib/Defaults/baileys-version.json +2 -2
  3. package/lib/Defaults/connection.js +1 -1
  4. package/lib/Defaults/constants.js +13 -1
  5. package/lib/Defaults/history.js +3 -1
  6. package/lib/Signal/Group/sender-chain-key.js +1 -14
  7. package/lib/Signal/Group/sender-key-distribution-message.js +2 -2
  8. package/lib/Signal/Group/sender-key-record.js +2 -11
  9. package/lib/Signal/Group/sender-key-state.js +11 -57
  10. package/lib/Signal/libsignal.js +200 -116
  11. package/lib/Signal/lid-mapping.js +121 -68
  12. package/lib/Socket/Client/websocket.js +9 -2
  13. package/lib/Socket/business.js +5 -1
  14. package/lib/Socket/chats.js +180 -89
  15. package/lib/Socket/community.js +169 -41
  16. package/lib/Socket/groups.js +25 -21
  17. package/lib/Socket/messages-recv.js +458 -333
  18. package/lib/Socket/messages-send.js +517 -572
  19. package/lib/Socket/mex.js +61 -0
  20. package/lib/Socket/newsletter.js +159 -252
  21. package/lib/Socket/socket.js +283 -100
  22. package/lib/Types/Newsletter.js +32 -25
  23. package/lib/Utils/auth-utils.js +189 -354
  24. package/lib/Utils/browser-utils.js +43 -0
  25. package/lib/Utils/chat-utils.js +166 -41
  26. package/lib/Utils/decode-wa-message.js +77 -35
  27. package/lib/Utils/event-buffer.js +80 -24
  28. package/lib/Utils/generics.js +28 -128
  29. package/lib/Utils/history.js +10 -8
  30. package/lib/Utils/index.js +1 -1
  31. package/lib/Utils/link-preview.js +17 -32
  32. package/lib/Utils/lt-hash.js +28 -22
  33. package/lib/Utils/make-mutex.js +26 -28
  34. package/lib/Utils/message-retry-manager.js +51 -3
  35. package/lib/Utils/messages-media.js +343 -151
  36. package/lib/Utils/messages.js +806 -792
  37. package/lib/Utils/noise-handler.js +33 -2
  38. package/lib/Utils/pre-key-manager.js +126 -0
  39. package/lib/Utils/process-message.js +115 -55
  40. package/lib/Utils/signal.js +45 -18
  41. package/lib/Utils/validate-connection.js +52 -29
  42. package/lib/WABinary/constants.js +1268 -1268
  43. package/lib/WABinary/decode.js +58 -4
  44. package/lib/WABinary/encode.js +54 -7
  45. package/lib/WABinary/jid-utils.js +58 -11
  46. package/lib/WAM/constants.js +19064 -11563
  47. package/lib/WAM/encode.js +57 -8
  48. package/lib/WAUSync/USyncQuery.js +35 -19
  49. package/package.json +9 -8
  50. package/lib/Socket/usync.js +0 -83
@@ -25,35 +25,44 @@ const generateIV = (counter) => {
25
25
 
26
26
  const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, logger, routingInfo }) => {
27
27
  logger = logger.child({ class: 'ns' })
28
+
28
29
  const authenticate = (data) => {
29
30
  if (!isFinished) {
30
31
  hash = sha256(Buffer.concat([hash, data]))
31
32
  }
32
33
  }
34
+
33
35
  const encrypt = (plaintext) => {
34
36
  const result = aesEncryptGCM(plaintext, encKey, generateIV(writeCounter), hash)
35
37
  writeCounter += 1
36
38
  authenticate(result)
37
39
  return result
38
40
  }
41
+
39
42
  const decrypt = (ciphertext) => {
40
43
  // before the handshake is finished, we use the same counter
41
44
  // after handshake, the counters are different
42
45
  const iv = generateIV(isFinished ? readCounter : writeCounter)
43
46
  const result = aesDecryptGCM(ciphertext, decKey, iv, hash)
47
+
44
48
  if (isFinished) {
45
49
  readCounter += 1
46
50
  }
51
+
47
52
  else {
48
53
  writeCounter += 1
49
54
  }
55
+
50
56
  authenticate(ciphertext)
57
+
51
58
  return result
52
59
  }
60
+
53
61
  const localHKDF = async (data) => {
54
62
  const key = await hkdf(Buffer.from(data), 64, { salt, info: '' })
55
63
  return [key.slice(0, 32), key.slice(32)]
56
64
  }
65
+
57
66
  const mixIntoKey = async (data) => {
58
67
  const [write, read] = await localHKDF(data)
59
68
  salt = write
@@ -62,6 +71,7 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
62
71
  readCounter = 0
63
72
  writeCounter = 0
64
73
  }
74
+
65
75
  const finishInit = async () => {
66
76
  const [write, read] = await localHKDF(new Uint8Array(0))
67
77
  encKey = write
@@ -71,7 +81,9 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
71
81
  writeCounter = 0
72
82
  isFinished = true
73
83
  }
84
+
74
85
  const data = Buffer.from(NOISE_MODE)
86
+
75
87
  let hash = data.byteLength === 32 ? data : sha256(data)
76
88
  let salt = hash
77
89
  let encKey = hash
@@ -81,8 +93,10 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
81
93
  let isFinished = false
82
94
  let sentIntro = false
83
95
  let inBytes = Buffer.alloc(0)
96
+
84
97
  authenticate(NOISE_HEADER)
85
98
  authenticate(publicKey)
99
+
86
100
  return {
87
101
  encrypt,
88
102
  decrypt,
@@ -95,20 +109,27 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
95
109
  const decStaticContent = decrypt(serverHello.static)
96
110
  await mixIntoKey(Curve.sharedKey(privateKey, decStaticContent))
97
111
  const certDecoded = decrypt(serverHello.payload)
98
- const { intermediate: certIntermediate } = proto.CertChain.decode(certDecoded)
112
+ const { intermediate: certIntermediate /*leaf*/ } = proto.CertChain.decode(certDecoded)
113
+ // TODO: handle this leaf stuff
99
114
  const { issuerSerial } = proto.CertChain.NoiseCertificate.Details.decode(certIntermediate.details)
115
+
100
116
  if (issuerSerial !== WA_CERT_DETAILS.SERIAL) {
101
117
  throw new Boom('certification match failed', { statusCode: 400 })
102
118
  }
119
+
103
120
  const keyEnc = encrypt(noiseKey.public)
121
+
104
122
  await mixIntoKey(Curve.sharedKey(noiseKey.private, serverHello.ephemeral))
123
+
105
124
  return keyEnc
106
125
  },
107
126
  encodeFrame: (data) => {
108
127
  if (isFinished) {
109
128
  data = encrypt(data)
110
129
  }
130
+
111
131
  let header
132
+
112
133
  if (routingInfo) {
113
134
  header = Buffer.alloc(7)
114
135
  header.write('ED', 0, 'utf8')
@@ -121,12 +142,15 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
121
142
  else {
122
143
  header = Buffer.from(NOISE_HEADER)
123
144
  }
145
+
124
146
  const introSize = sentIntro ? 0 : header.length
125
147
  const frame = Buffer.alloc(introSize + 3 + data.byteLength)
148
+
126
149
  if (!sentIntro) {
127
150
  frame.set(header)
128
151
  sentIntro = true
129
152
  }
153
+
130
154
  frame.writeUInt8(data.byteLength >> 16, introSize)
131
155
  frame.writeUInt16BE(65535 & data.byteLength, introSize + 1)
132
156
  frame.set(data, introSize + 3)
@@ -141,18 +165,25 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
141
165
  return (inBytes.readUInt8() << 16) | inBytes.readUInt16BE(1)
142
166
  }
143
167
  }
168
+
144
169
  inBytes = Buffer.concat([inBytes, newData])
145
170
  logger.trace(`recv ${newData.length} bytes, total recv ${inBytes.length} bytes`)
171
+
146
172
  let size = getBytesSize()
147
173
  while (size && inBytes.length >= size + 3) {
148
174
  let frame = inBytes.slice(3, size + 3)
149
- inBytes = inBytes.slice(size + 3)
175
+
176
+ inBytes = inBytes.slice(size + 3)
177
+
150
178
  if (isFinished) {
151
179
  const result = decrypt(frame)
152
180
  frame = await decodeBinaryNode(result)
153
181
  }
182
+
154
183
  logger.trace({ msg: frame?.attrs?.id }, 'recv frame')
184
+
155
185
  onFrame(frame)
186
+
156
187
  size = getBytesSize()
157
188
  }
158
189
  }
@@ -0,0 +1,126 @@
1
+ "use strict"
2
+
3
+ Object.defineProperty(exports, "__esModule", { value: true })
4
+
5
+ const { default: PQueue } = require("p-queue")
6
+
7
+ /**
8
+ * Manages pre-key operations with proper concurrency control
9
+ */
10
+ class PreKeyManager {
11
+ constructor(store, logger) {
12
+ this.store = store
13
+ this.logger = logger
14
+ this.queues = new Map()
15
+ }
16
+
17
+ /**
18
+ * Get or create a queue for a specific key type
19
+ */
20
+ getQueue(keyType) {
21
+ if (!this.queues.has(keyType)) {
22
+ this.queues.set(keyType, new PQueue({ concurrency: 1 }))
23
+ }
24
+ return this.queues.get(keyType)
25
+ }
26
+
27
+ /**
28
+ * Process pre-key operations (updates and deletions)
29
+ */
30
+ async processOperations(data, keyType, transactionCache, mutations, isInTransaction) {
31
+ const keyData = data[keyType]
32
+
33
+ if (!keyData) return
34
+
35
+ return this.getQueue(keyType).add(async () => {
36
+ // Ensure structures exist
37
+ transactionCache[keyType] = transactionCache[keyType] || {}
38
+ mutations[keyType] = mutations[keyType] || {}
39
+
40
+ // Separate deletions from updates
41
+ const deletions = []
42
+ const updates = {}
43
+
44
+ for (const keyId in keyData) {
45
+ if (keyData[keyId] === null) {
46
+ deletions.push(keyId)
47
+ }
48
+ else {
49
+ updates[keyId] = keyData[keyId]
50
+ }
51
+ }
52
+
53
+ // Process updates (no validation needed)
54
+ if (Object.keys(updates).length > 0) {
55
+ Object.assign(transactionCache[keyType], updates)
56
+ Object.assign(mutations[keyType], updates)
57
+ }
58
+
59
+ // Process deletions with validation
60
+ if (deletions.length > 0) {
61
+ await this.processDeletions(keyType, deletions, transactionCache, mutations, isInTransaction)
62
+ }
63
+ })
64
+ }
65
+
66
+ /**
67
+ * Process deletions with validation
68
+ */
69
+ async processDeletions(keyType, ids, transactionCache, mutations, isInTransaction) {
70
+ if (isInTransaction) {
71
+ // In transaction, only allow deletion if key exists in cache
72
+ for (const keyId of ids) {
73
+ if (transactionCache[keyType]?.[keyId]) {
74
+ transactionCache[keyType][keyId] = null
75
+ mutations[keyType][keyId] = null
76
+ }
77
+ else {
78
+ this.logger.warn(`Skipping deletion of non-existent ${keyType} in transaction: ${keyId}`)
79
+ }
80
+ }
81
+ }
82
+ else {
83
+ // Outside transaction, validate against store
84
+ const existingKeys = await this.store.get(keyType, ids)
85
+ for (const keyId of ids) {
86
+ if (existingKeys[keyId]) {
87
+ transactionCache[keyType][keyId] = null
88
+ mutations[keyType][keyId] = null
89
+ }
90
+ else {
91
+ this.logger.warn(`Skipping deletion of non-existent ${keyType}: ${keyId}`)
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ /**
98
+ * Validate and process pre-key deletions outside transactions
99
+ */
100
+ async validateDeletions(data, keyType) {
101
+ const keyData = data[keyType]
102
+
103
+ if (!keyData) return
104
+
105
+ return this.getQueue(keyType).add(async () => {
106
+ // Find all deletion requests
107
+ const deletionIds = Object.keys(keyData).filter(id => keyData[id] === null)
108
+
109
+ if (deletionIds.length === 0) return
110
+
111
+ // Validate deletions
112
+ const existingKeys = await this.store.get(keyType, deletionIds)
113
+
114
+ for (const keyId of deletionIds) {
115
+ if (!existingKeys[keyId]) {
116
+ this.logger.warn(`Skipping deletion of non-existent ${keyType}: ${keyId}`)
117
+ delete data[keyType][keyId]
118
+ }
119
+ }
120
+ })
121
+ }
122
+ }
123
+
124
+ module.exports = {
125
+ PreKeyManager
126
+ }
@@ -11,8 +11,13 @@ const {
11
11
  } = require("../Utils")
12
12
  const {
13
13
  areJidsSameUser,
14
+ isHostedLidUser,
15
+ isHostedPnUser,
14
16
  isJidBroadcast,
15
- isJidStatusBroadcast,
17
+ isJidStatusBroadcast,
18
+ isLidUser,
19
+ jidDecode,
20
+ jidEncode,
16
21
  jidNormalizedUser
17
22
  } = require("../WABinary")
18
23
  const {
@@ -37,18 +42,32 @@ const REAL_MSG_REQ_ME_STUB_TYPES = new Set([
37
42
  ])
38
43
 
39
44
  /** Cleans a received message to further processing */
40
- const cleanMessage = (message, meId) => {
45
+ const cleanMessage = (message, meId, meLid) => {
41
46
  // ensure remoteJid and participant doesn't have device or agent in it
42
- message.key.remoteJid = jidNormalizedUser(message.key.remoteJid)
43
- message.key.participant = message.key.participant ? jidNormalizedUser(message.key.participant) : undefined
47
+ if (isHostedPnUser(message.key.remoteJid) || isHostedLidUser(message.key.remoteJid)) {
48
+ message.key.remoteJid = jidEncode(jidDecode(message.key?.remoteJid)?.user, isHostedPnUser(message.key.remoteJid) ? 's.whatsapp.net' : 'lid')
49
+ }
50
+ else {
51
+ message.key.remoteJid = jidNormalizedUser(message.key.remoteJid)
52
+ }
53
+
54
+ if (isHostedPnUser(message.key.participant) || isHostedLidUser(message.key.participant)) {
55
+ message.key.participant = jidEncode(jidDecode(message.key.participant)?.user, isHostedPnUser(message.key.participant) ? 's.whatsapp.net' : 'lid')
56
+ }
57
+ else {
58
+ message.key.participant = jidNormalizedUser(message.key.participant)
59
+ }
44
60
  const content = normalizeMessageContent(message.message)
61
+
45
62
  // if the message has a reaction, ensure fromMe & remoteJid are from our perspective
46
63
  if (content?.reactionMessage) {
47
64
  normaliseKey(content.reactionMessage.key)
48
65
  }
66
+
49
67
  if (content?.pollUpdateMessage) {
50
68
  normaliseKey(content.pollUpdateMessage.pollCreationMessageKey)
51
69
  }
70
+
52
71
  function normaliseKey(msgKey) {
53
72
  // if the reaction is from another user
54
73
  // we've to correctly map the key to this user's perspective
@@ -56,11 +75,13 @@ const cleanMessage = (message, meId) => {
56
75
  // if the sender believed the message being reacted to is not from them
57
76
  // we've to correct the key to be from them, or some other participant
58
77
  msgKey.fromMe = !msgKey.fromMe
59
- ? areJidsSameUser(msgKey.participant || msgKey.remoteJid, meId)
60
- // if the message being reacted to, was from them
61
- // fromMe automatically becomes false
62
- : false
78
+ ? areJidsSameUser(msgKey.participant || msgKey.remoteJid, meId) ||
79
+ areJidsSameUser(msgKey.participant || msgKey.remoteJid, meLid)
80
+ : // if the message being reacted to, was from them
81
+ // fromMe automatically becomes false
82
+ false
63
83
  // set the remoteJid to being the same as the chat the message came from
84
+ // TODO: investigate inconsistencies
64
85
  msgKey.remoteJid = message.key.remoteJid
65
86
  // set participant of the message
66
87
  msgKey.participant = msgKey.participant || message.key.participant
@@ -68,24 +89,20 @@ const cleanMessage = (message, meId) => {
68
89
  }
69
90
  }
70
91
 
71
- const isRealMessage = (message, meId) => {
92
+ // TODO: target:audit AUDIT THIS FUNCTION AGAIN
93
+ const isRealMessage = (message) => {
72
94
  const normalizedContent = normalizeMessageContent(message.message)
73
95
  const hasSomeContent = !!getContentType(normalizedContent)
74
- return (
75
- !!normalizedContent ||
96
+ return ((!!normalizedContent ||
76
97
  REAL_MSG_STUB_TYPES.has(message.messageStubType) ||
77
- (
78
- REAL_MSG_REQ_ME_STUB_TYPES.has(message.messageStubType) &&
79
- message.messageStubParameters?.some(p => areJidsSameUser(meId, p))
80
- )
81
- ) &&
82
- hasSomeContent &&
83
- !normalizedContent?.protocolMessage &&
84
- !normalizedContent?.reactionMessage &&
85
- !normalizedContent?.pollUpdateMessage
98
+ REAL_MSG_REQ_ME_STUB_TYPES.has(message.messageStubType)) &&
99
+ hasSomeContent &&
100
+ !normalizedContent?.protocolMessage &&
101
+ !normalizedContent?.reactionMessage &&
102
+ !normalizedContent?.pollUpdateMessage)
86
103
  }
87
104
 
88
- const shouldIncrementChatUnread = (message) => (!message.key.fromMe && !message.messageStubType)
105
+ const shouldIncrementChatUnread = (message) => !message.key.fromMe && !message.messageStubType
89
106
 
90
107
  /**
91
108
  * Get the ID of the chat from the given key.
@@ -233,7 +250,7 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
233
250
  const meLid = creds.me.lid
234
251
  const { accountSettings } = creds
235
252
  const chat = { id: jidNormalizedUser(getChatId(message.key)) }
236
- const isRealMsg = isRealMessage(message, meId)
253
+ const isRealMsg = isRealMessage(message)
237
254
  if (isRealMsg) {
238
255
  chat.messages = [{ message }]
239
256
  chat.conversationTimestamp = toNumber(message.messageTimestamp)
@@ -257,13 +274,16 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
257
274
  const histNotification = protocolMsg.historySyncNotification
258
275
  const process = shouldProcessHistoryMsg
259
276
  const isLatest = !creds.processedHistoryMessages?.length
277
+
260
278
  logger?.info({
261
279
  histNotification,
262
280
  process,
263
281
  id: message.key.id,
264
- isLatest,
282
+ isLatest
265
283
  }, 'got history notification')
284
+
266
285
  if (process) {
286
+ // TODO: investigate
267
287
  if (histNotification.syncType !== proto.HistorySync.HistorySyncType.ON_DEMAND) {
268
288
  ev.emit('creds.update', {
269
289
  processedHistoryMessages: [
@@ -272,32 +292,39 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
272
292
  ]
273
293
  })
274
294
  }
295
+
275
296
  const data = await downloadAndProcessHistorySyncNotification(histNotification, options)
276
297
  ev.emit('messaging-history.set', {
277
298
  ...data,
278
- isLatest: histNotification.syncType !== proto.HistorySync.HistorySyncType.ON_DEMAND
279
- ? isLatest
280
- : undefined,
299
+ isLatest: histNotification.syncType !== proto.HistorySync.HistorySyncType.ON_DEMAND ? isLatest : undefined,
281
300
  peerDataRequestSessionId: histNotification.peerDataRequestSessionId
282
301
  })
283
302
  }
284
303
  break
285
304
  case proto.Message.ProtocolMessage.Type.APP_STATE_SYNC_KEY_SHARE:
286
305
  const keys = protocolMsg.appStateSyncKeyShare.keys
306
+
287
307
  if (keys?.length) {
288
308
  let newAppStateSyncKeyId = ''
309
+
289
310
  await keyStore.transaction(async () => {
290
311
  const newKeys = []
312
+
291
313
  for (const { keyData, keyId } of keys) {
292
314
  const strKeyId = Buffer.from(keyId.keyId).toString('base64')
315
+
293
316
  newKeys.push(strKeyId)
317
+
294
318
  await keyStore.set({ 'app-state-sync-key': { [strKeyId]: keyData } })
319
+
295
320
  newAppStateSyncKeyId = strKeyId
296
321
  }
322
+
297
323
  logger?.info({ newAppStateSyncKeyId, newKeys }, 'injecting new app state sync keys')
298
324
  }, meId)
299
325
  ev.emit('creds.update', { myAppStateKeyId: newAppStateSyncKeyId })
300
326
  }
327
+
301
328
  else {
302
329
  logger?.info({ protocolMsg }, 'recv app state sync with 0 keys')
303
330
  }
@@ -321,16 +348,21 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
321
348
  break
322
349
  case proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_RESPONSE_MESSAGE:
323
350
  const response = protocolMsg.peerDataOperationRequestResponseMessage
351
+
324
352
  if (response) {
325
- await laceholderResendCache?.del(response.stanzaId)
353
+ await placeholderResendCache?.del(response.stanzaId)
354
+
326
355
  // TODO: IMPLEMENT HISTORY SYNC ETC (sticker uploads etc.).
327
356
  const { peerDataOperationResult } = response
357
+
328
358
  for (const result of peerDataOperationResult) {
329
359
  const { placeholderMessageResendResponse: retryResponse } = result
360
+
330
361
  //eslint-disable-next-line max-depth
331
362
  if (retryResponse) {
332
363
  const webMessageInfo = proto.WebMessageInfo.decode(retryResponse.webMessageInfoBytes)
333
364
  // wait till another upsert event is available, don't want it to be part of the PDO response message
365
+ // TODO: parse through proper message handling utilities (to add relevant key fields)
334
366
  setTimeout(() => {
335
367
  ev.emit('messages.upsert', {
336
368
  messages: [webMessageInfo],
@@ -360,8 +392,22 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
360
392
  }
361
393
  ])
362
394
  break
395
+ case proto.Message.ProtocolMessage.Type.GROUP_MEMBER_LABEL_CHANGE:
396
+ const labelAssociationMsg = protocolMsg.memberLabel
397
+
398
+ if (labelAssociationMsg?.label) {
399
+ ev.emit('group.member-tag.update', {
400
+ groupId: chat.id,
401
+ label: labelAssociationMsg.label,
402
+ participant: message.key.participant,
403
+ participantAlt: message.key.participantAlt,
404
+ messageTimestamp: Number(message.messageTimestamp)
405
+ })
406
+ }
407
+ break
363
408
  case proto.Message.ProtocolMessage.Type.LID_MIGRATION_MAPPING_SYNC:
364
409
  const encodedPayload = protocolMsg.lidMigrationMappingSyncMessage?.encodedMappingPayload
410
+
365
411
  const { pnToLidMappings, chatDbMigrationTimestamp } = proto.LIDMigrationMappingSyncPayload.decode(encodedPayload)
366
412
 
367
413
  logger?.debug({ pnToLidMappings, chatDbMigrationTimestamp }, 'got lid mappings and chat db migration timestamp')
@@ -374,6 +420,12 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
374
420
  }
375
421
 
376
422
  await signalRepository.lidMapping.storeLIDPNMappings(pairs)
423
+
424
+ if (pairs.length) {
425
+ for (const { pn, lid } of pairs) {
426
+ await signalRepository.migrateSession(pn, lid)
427
+ }
428
+ }
377
429
  break
378
430
  case proto.Message.ProtocolMessage.Type.LIMIT_SHARING:
379
431
  ev.emit('limit-sharing.update', {
@@ -398,32 +450,46 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
398
450
  }
399
451
  else if (message.messageStubType) {
400
452
  const jid = message.key?.remoteJid
401
- //let actor = whatsappID (message.participant)
453
+
402
454
  let participants
403
- const emitParticipantsUpdate = (action) => (ev.emit('group-participants.update', { id: jid, author: message.participant, participants, action }))
455
+
456
+ const emitParticipantsUpdate = (action) => ev.emit('group-participants.update', {
457
+ id: jid,
458
+ author: message.key.participant,
459
+ authorPn: message.key.participantAlt,
460
+ participants,
461
+ action
462
+ })
463
+
404
464
  const emitGroupUpdate = (update) => {
405
- ev.emit('groups.update', [{ id: jid, ...update, author: message.participant ? message.participant : undefined }])
465
+ ev.emit('groups.update', [
466
+ { id: jid, ...update, author: message.key.participant ?? undefined, authorPn: message.key.participantAlt }
467
+ ])
406
468
  }
469
+
407
470
  const emitGroupRequestJoin = (participant, action, method) => {
408
- ev.emit('group.join-request', { id: jid, author: message.participant, participant, action, method: method })
471
+ ev.emit('group.join-request', {
472
+ id: jid,
473
+ author: message.key.participant,
474
+ authorPn: message.key.participantAlt,
475
+ participant: participant.lid,
476
+ participantPn: participant.pn,
477
+ action,
478
+ method: method
479
+ })
409
480
  }
410
- const participantsIncludesMe = () => participants.find(jid => areJidsSameUser(meId, jid))
481
+
482
+ const participantsIncludesMe = () => participants.find(jid => areJidsSameUser(meId, jid.phoneNumber)) // ADD SUPPORT FOR LID
411
483
  switch (message.messageStubType) {
412
484
  case WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER:
413
- participants = message.messageStubParameters || []
485
+ participants = message.messageStubParameters.map((a) => JSON.parse(a)) || []
414
486
  emitParticipantsUpdate('modify')
415
487
  break
416
488
  case WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
417
- participants = message.messageStubParameters || [];
418
- emitParticipantsUpdate('leave');
419
- // mark the chat read only if you left the group
420
- if (participantsIncludesMe()) {
421
- chat.readOnly = true;
422
- }
423
- break;
424
489
  case WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
425
- participants = message.messageStubParameters || []
490
+ participants = message.messageStubParameters.map((a) => JSON.parse(a)) || []
426
491
  emitParticipantsUpdate('remove')
492
+
427
493
  // mark the chat read only if you left the group
428
494
  if (participantsIncludesMe()) {
429
495
  chat.readOnly = true
@@ -431,27 +497,21 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
431
497
  break
432
498
  case WAMessageStubType.GROUP_PARTICIPANT_ADD:
433
499
  case WAMessageStubType.GROUP_PARTICIPANT_INVITE:
434
- let actionGp = 'invite'
435
- participants = message.messageStubParameters || []
436
- if (participantsIncludesMe()) chat.readOnly = false;
437
- if (message?.key?.participant && !participants.includes(message?.key?.participant)) {
438
- actionGp = 'approval-invite'
439
- }
440
500
  case WAMessageStubType.GROUP_PARTICIPANT_ADD_REQUEST_JOIN:
441
- participants = message.messageStubParameters || []
501
+ participants = message.messageStubParameters.map((a) => JSON.parse(a)) || []
502
+
442
503
  if (participantsIncludesMe()) {
443
504
  chat.readOnly = false
444
505
  }
506
+
445
507
  emitParticipantsUpdate('add')
446
508
  break
447
509
  case WAMessageStubType.GROUP_PARTICIPANT_DEMOTE:
448
- case WAMessageStubType.COMMUNITY_PARTICIPANT_DEMOTE:
449
- participants = message.messageStubParameters || []
510
+ participants = message.messageStubParameters.map((a) => JSON.parse(a)) || []
450
511
  emitParticipantsUpdate('demote')
451
512
  break
452
513
  case WAMessageStubType.GROUP_PARTICIPANT_PROMOTE:
453
- case WAMessageStubType.COMMUNITY_PARTICIPANT_PROMOTE:
454
- participants = message.messageStubParameters || []
514
+ participants = message.messageStubParameters.map((a) => JSON.parse(a)) || []
455
515
  emitParticipantsUpdate('promote')
456
516
  break
457
517
  case WAMessageStubType.GROUP_CHANGE_ANNOUNCE:
@@ -484,8 +544,8 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
484
544
  const approvalMode = message.messageStubParameters?.[0]
485
545
  emitGroupUpdate({ joinApprovalMode: approvalMode === 'on' })
486
546
  break
487
- case WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD:
488
- const participant = message.messageStubParameters?.[0]
547
+ case WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD: // TODO: Add other events
548
+ const participant = JSON.parse(message.messageStubParameters?.[0])
489
549
  const action = message.messageStubParameters?.[1]
490
550
  const method = message.messageStubParameters?.[2]
491
551
  emitGroupRequestJoin(participant, action, method)
@@ -650,7 +710,7 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
650
710
  const encComment = content.encCommentMessage
651
711
  const creationMsgKey = encComment.targetMessageKey
652
712
 
653
- // we need to fetch the message to get the reaction enc key
713
+ // we need to fetch the message to get the comment enc key
654
714
  const commentMsg = await getMessage(creationMsgKey)
655
715
  if (commentMsg) {
656
716
  try {