@pontalabs/baileys 1.0.10 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/README.md +96 -85
  2. package/lib/Defaults/connection.js +39 -0
  3. package/lib/Defaults/constants.js +50 -0
  4. package/lib/Defaults/history.js +13 -0
  5. package/lib/Defaults/index.js +36 -151
  6. package/lib/Defaults/media.js +43 -0
  7. package/lib/Defaults/phonenumber-mcc.json +221 -221
  8. package/lib/Defaults/prefix.js +12 -0
  9. package/lib/Defaults/vialeys-version.json +7 -0
  10. package/lib/Signal/Group/ciphertext-message.js +10 -15
  11. package/lib/Signal/Group/group-session-builder.js +34 -60
  12. package/lib/Signal/Group/group_cipher.js +69 -76
  13. package/lib/Signal/Group/index.js +41 -60
  14. package/lib/Signal/Group/keyhelper.js +12 -57
  15. package/lib/Signal/Group/sender-chain-key.js +20 -33
  16. package/lib/Signal/Group/sender-key-distribution-message.js +43 -48
  17. package/lib/Signal/Group/sender-key-message.js +58 -53
  18. package/lib/Signal/Group/sender-key-name.js +21 -31
  19. package/lib/Signal/Group/sender-key-record.js +21 -34
  20. package/lib/Signal/Group/sender-key-state.js +59 -106
  21. package/lib/Signal/Group/sender-message-key.js +16 -21
  22. package/lib/Signal/libsignal.js +282 -203
  23. package/lib/Signal/lid-mapping.js +164 -184
  24. package/lib/Socket/Client/index.js +31 -22
  25. package/lib/Socket/Client/types.js +9 -15
  26. package/lib/Socket/Client/websocket.js +42 -37
  27. package/lib/Socket/business.js +212 -336
  28. package/lib/Socket/chats.js +696 -940
  29. package/lib/Socket/community.js +454 -369
  30. package/lib/Socket/groups.js +278 -280
  31. package/lib/Socket/index.js +9 -21
  32. package/lib/Socket/messages-recv.js +1027 -1570
  33. package/lib/Socket/messages-send.js +1180 -1136
  34. package/lib/Socket/mex.js +59 -0
  35. package/lib/Socket/newsletter.js +193 -251
  36. package/lib/Socket/socket.js +758 -898
  37. package/lib/Store/index.js +35 -24
  38. package/lib/Store/make-cache-manager-store.js +53 -66
  39. package/lib/Store/make-in-memory-store.js +319 -325
  40. package/lib/Store/make-ordered-dictionary.js +49 -57
  41. package/lib/Store/object-repository.js +10 -15
  42. package/lib/Types/Auth.js +2 -3
  43. package/lib/Types/Bussines.js +2 -3
  44. package/lib/Types/Call.js +2 -3
  45. package/lib/Types/Chat.js +10 -9
  46. package/lib/Types/Contact.js +2 -3
  47. package/lib/Types/Events.js +2 -3
  48. package/lib/Types/GroupMetadata.js +2 -3
  49. package/lib/Types/Label.js +6 -12
  50. package/lib/Types/LabelAssociation.js +4 -13
  51. package/lib/Types/Message.js +10 -18
  52. package/lib/Types/MexUpdates.js +15 -18
  53. package/lib/Types/Newsletter.js +26 -34
  54. package/lib/Types/Product.js +2 -3
  55. package/lib/Types/Signal.js +2 -3
  56. package/lib/Types/Socket.js +2 -3
  57. package/lib/Types/State.js +8 -13
  58. package/lib/Types/USync.js +2 -3
  59. package/lib/Types/index.js +49 -40
  60. package/lib/Utils/auth-utils.js +190 -495
  61. package/lib/Utils/browser-utils.js +29 -0
  62. package/lib/Utils/business.js +177 -199
  63. package/lib/Utils/chat-utils.js +711 -624
  64. package/lib/Utils/crypto.js +116 -161
  65. package/lib/Utils/decode-wa-message.js +225 -321
  66. package/lib/Utils/event-buffer.js +363 -405
  67. package/lib/Utils/generics.js +318 -472
  68. package/lib/Utils/history.js +72 -76
  69. package/lib/Utils/index.js +49 -41
  70. package/lib/Utils/link-preview.js +59 -103
  71. package/lib/Utils/logger.js +4 -7
  72. package/lib/Utils/lt-hash.js +29 -42
  73. package/lib/Utils/make-mutex.js +26 -42
  74. package/lib/Utils/message-retry-manager.js +134 -160
  75. package/lib/Utils/messages-media.js +665 -731
  76. package/lib/Utils/messages.js +518 -1
  77. package/lib/Utils/noise-handler.js +127 -125
  78. package/lib/Utils/pre-key-manager.js +86 -0
  79. package/lib/Utils/process-message.js +739 -351
  80. package/lib/Utils/signal.js +146 -129
  81. package/lib/Utils/use-multi-file-auth-state.js +68 -135
  82. package/lib/Utils/validate-connection.js +183 -142
  83. package/lib/Utils/vialeys-event-stream.js +41 -0
  84. package/lib/WABinary/constants.js +1281 -1289
  85. package/lib/WABinary/decode.js +145 -200
  86. package/lib/WABinary/encode.js +149 -202
  87. package/lib/WABinary/generic-utils.js +79 -97
  88. package/lib/WABinary/index.js +36 -25
  89. package/lib/WABinary/jid-utils.js +91 -123
  90. package/lib/WABinary/types.js +2 -3
  91. package/lib/WAM/BinaryInfo.js +8 -13
  92. package/lib/WAM/constants.js +16584 -11464
  93. package/lib/WAM/encode.js +117 -133
  94. package/lib/WAM/index.js +34 -23
  95. package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +62 -69
  96. package/lib/WAUSync/Protocols/USyncContactProtocol.js +11 -25
  97. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +32 -44
  98. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +13 -23
  99. package/lib/WAUSync/Protocols/USyncLIDProtocol.js +24 -38
  100. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +17 -31
  101. package/lib/WAUSync/Protocols/index.js +37 -26
  102. package/lib/WAUSync/USyncQuery.js +66 -66
  103. package/lib/WAUSync/USyncUser.js +13 -18
  104. package/lib/WAUSync/index.js +34 -23
  105. package/lib/index.js +95 -28
  106. package/package.json +4 -3
  107. package/lib/Defaults/baileys-version.json +0 -3
  108. package/lib/Signal/Group/queue-job.d.ts +0 -1
  109. package/lib/Signal/Group/queue-job.js +0 -57
  110. package/lib/Socket/usync.d.ts +0 -37
  111. package/lib/Socket/usync.js +0 -83
  112. package/lib/Utils/baileys-event-stream.d.ts +0 -18
  113. package/lib/Utils/baileys-event-stream.js +0 -70
  114. package/lib/Utils/signal-housekeeping.d.ts +0 -19
  115. package/lib/Utils/signal-housekeeping.js +0 -73
  116. package/lib/Utils/use-mongo-file-auth-state.d.ts +0 -6
  117. package/lib/Utils/use-mongo-file-auth-state.js +0 -84
  118. package/lib/Utils/use-single-file-auth-state.d.ts +0 -13
  119. package/lib/Utils/use-single-file-auth-state.js +0 -80
@@ -1,23 +1,28 @@
1
- "use strict"
2
-
3
- Object.defineProperty(exports, "__esModule", { value: true })
4
-
5
- const boom_1 = require("@hapi/boom")
6
- const WAProto_1 = require("../../WAProto")
7
- const WABinary_1 = require("../WABinary")
8
- const generics_1 = require("./generics")
9
- const messages_1 = require("./messages")
10
-
11
- const NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node'
12
-
13
- const MISSING_KEYS_ERROR_TEXT = 'Key used already or never filled'
14
-
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const { Boom: Boom } = require("@hapi/boom");
4
+ const { proto: proto } = require("../../WAProto");
5
+ const {
6
+ areJidsSameUser: areJidsSameUser,
7
+ isHostedLidUser: isHostedLidUser,
8
+ isHostedPnUser: isHostedPnUser,
9
+ isJidBroadcast: isJidBroadcast,
10
+ isJidGroup: isJidGroup,
11
+ isJidMetaAI: isJidMetaAI,
12
+ isJidNewsletter: isJidNewsletter,
13
+ isJidStatusBroadcast: isJidStatusBroadcast,
14
+ isLidUser: isLidUser,
15
+ isPnUser: isPnUser,
16
+ } = require("../WABinary");
17
+ const { unpadRandomMax16: unpadRandomMax16 } = require("./generics");
18
+ const { getDevice: getDevice } = require("./messages");
19
+ const NO_MESSAGE_FOUND_ERROR_TEXT = "Message absent from node";
20
+ const MISSING_KEYS_ERROR_TEXT = "Key used already or never filled";
15
21
  const DECRYPTION_RETRY_CONFIG = {
16
22
  maxRetries: 3,
17
23
  baseDelayMs: 100,
18
- sessionRecordErrors: ['No session record', 'SessionError: No session record']
19
- }
20
-
24
+ sessionRecordErrors: ["No session record", "SessionError: No session record"],
25
+ };
21
26
  const NACK_REASONS = {
22
27
  ParsingError: 487,
23
28
  UnrecognizedStanza: 488,
@@ -31,371 +36,270 @@ const NACK_REASONS = {
31
36
  UnhandledError: 500,
32
37
  UnsupportedAdminRevoke: 550,
33
38
  UnsupportedLIDGroup: 551,
34
- DBOperationFailed: 552
35
- }
36
-
37
- function getTypeMessage(message) {
38
- const type = Object.keys(message)
39
- const restype = (!['senderKeyDistributionMessage', 'messageContextInfo'].includes(type[0]) && type[0]) || (type.length >= 3 && type[1] !== 'messageContextInfo' && type[1]) || type[type.length - 1] || Object.keys(message)[0]
40
- return restype
41
- }
42
-
39
+ DBOperationFailed: 552,
40
+ };
41
+ const extractAddressingContext = (stanza) => {
42
+ let senderAlt;
43
+ let recipientAlt;
44
+ const sender = stanza.attrs.participant || stanza.attrs.from;
45
+ const addressingMode = stanza.attrs.addressing_mode || (sender?.endsWith("lid") ? "lid" : "pn");
46
+ if (addressingMode === "lid") {
47
+ senderAlt =
48
+ stanza.attrs.participant_pn || stanza.attrs.sender_pn || stanza.attrs.peer_recipient_pn;
49
+ recipientAlt = stanza.attrs.recipient_pn;
50
+ } else {
51
+ senderAlt =
52
+ stanza.attrs.participant_lid ||
53
+ stanza.attrs.sender_lid ||
54
+ stanza.attrs.peer_recipient_lid;
55
+ recipientAlt = stanza.attrs.recipient_lid;
56
+ }
57
+ return {
58
+ addressingMode: addressingMode,
59
+ senderAlt: senderAlt,
60
+ recipientAlt: recipientAlt,
61
+ };
62
+ };
63
+ const getDecryptionJid = async (sender, repository) => {
64
+ if (isLidUser(sender) || isHostedLidUser(sender)) {
65
+ return sender;
66
+ }
67
+ const mapped = await repository.lidMapping.getLIDForPN(sender);
68
+ return mapped || sender;
69
+ };
70
+ const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJid, logger) => {
71
+ const { senderAlt: senderAlt } = extractAddressingContext(stanza);
72
+ if (senderAlt && isLidUser(senderAlt) && isPnUser(sender) && decryptionJid === sender) {
73
+ try {
74
+ await repository.lidMapping.storeLIDPNMappings([{ lid: senderAlt, pn: sender }]);
75
+ await repository.migrateSession(sender, senderAlt);
76
+ logger.debug(
77
+ { sender: sender, senderAlt: senderAlt },
78
+ "Stored LID mapping from envelope"
79
+ );
80
+ } catch (error) {
81
+ logger.warn(
82
+ { sender: sender, senderAlt: senderAlt, error: error },
83
+ "Failed to store LID mapping"
84
+ );
85
+ }
86
+ }
87
+ };
43
88
  function decodeMessageNode(stanza, meId, meLid) {
44
- let msg_type
45
- let chat_id
46
- let author
47
- const msgId = stanza.attrs.id
48
- const from = stanza.attrs.from
49
- const participant = stanza.attrs.addressing_mode === "lid" ? stanza.attrs.participant_pn : stanza.attrs.addressing_mode === "pn" ? stanza.attrs.participant : from;
50
- const participant_lid = stanza.attrs.addressing_mode === "lid" ? stanza.attrs.participant : stanza.attrs.addressing_mode === "pn" ? stanza.attrs.participant_lid : stanza.attrs.sender_lid;
51
- const recipient = stanza.attrs.recipient
52
- const isMe = (jid) => WABinary_1.areJidsSameUser(jid, meId)
53
- const isMeLid = (jid) => WABinary_1.areJidsSameUser(jid, meLid)
54
- if (WABinary_1.isJidUser(from)) {
55
- if (recipient) {
56
- if (!isMe(from)) {
57
- throw new boom_1.Boom('receipient present, but msg not from me', { data: stanza })
89
+ let msgType;
90
+ let chatId;
91
+ let author;
92
+ let fromMe = false;
93
+ const msgId = stanza.attrs.id;
94
+ const from = stanza.attrs.from;
95
+ const participant = stanza.attrs.participant;
96
+ const recipient = stanza.attrs.recipient;
97
+ const addressingContext = extractAddressingContext(stanza);
98
+ const isMe = (jid) => areJidsSameUser(jid, meId);
99
+ const isMeLid = (jid) => areJidsSameUser(jid, meLid);
100
+ if (isPnUser(from) || isLidUser(from) || isHostedLidUser(from) || isHostedPnUser(from)) {
101
+ if (recipient && !isJidMetaAI(recipient)) {
102
+ if (!isMe(from) && !isMeLid(from)) {
103
+ throw new Boom("receipient present, but msg not from me", {
104
+ data: stanza,
105
+ });
58
106
  }
59
- chat_id = recipient
60
- }
61
- else {
62
- chat_id = from
63
- }
64
- msg_type = 'chat'
65
- author = from
66
- } else if (WABinary_1.isLidUser(from)) {
67
- if (recipient) {
68
- if (!isMeLid(from)) {
69
- throw new boom_1.Boom('receipient present, but msg not from me', { data: stanza })
107
+ if (isMe(from) || isMeLid(from)) {
108
+ fromMe = true;
70
109
  }
71
- // FIX: recipient mungkin LID juga, gunakan peer_recipient_pn jika ada
72
- chat_id = stanza.attrs.peer_recipient_pn
73
- ? WABinary_1.jidNormalizedUser(stanza.attrs.peer_recipient_pn)
74
- : recipient
75
- }
76
- else {
77
- // FIX: chat_id dari LID → resolve ke JID via sender_pn
78
- chat_id = stanza.attrs.sender_pn
79
- ? WABinary_1.jidNormalizedUser(stanza.attrs.sender_pn)
80
- : stanza.attrs.peer_recipient_pn
81
- ? WABinary_1.jidNormalizedUser(stanza.attrs.peer_recipient_pn)
82
- : from
110
+ chatId = recipient;
111
+ } else {
112
+ chatId = from;
83
113
  }
84
- msg_type = 'chat'
85
- // FIX: untuk private LID chat, gunakan sender_pn/participant_pn sebagai author
86
- // agar key.remoteJid dan author tidak berupa LID mentah
87
- author = stanza.attrs.sender_pn
88
- || stanza.attrs.participant_pn
89
- || stanza.attrs.peer_recipient_pn
90
- || from
91
- } else if (WABinary_1.isJidGroup(from)) {
114
+ msgType = "chat";
115
+ author = from;
116
+ } else if (isJidGroup(from)) {
92
117
  if (!participant) {
93
- throw new boom_1.Boom('No participant in group message')
118
+ throw new Boom("No participant in group message");
94
119
  }
95
- msg_type = 'group'
96
- author = participant
97
- chat_id = from
98
- } else if (WABinary_1.isJidBroadcast(from)) {
120
+ if (isMe(participant) || isMeLid(participant)) {
121
+ fromMe = true;
122
+ }
123
+ msgType = "group";
124
+ author = participant;
125
+ chatId = from;
126
+ } else if (isJidBroadcast(from)) {
99
127
  if (!participant) {
100
- throw new boom_1.Boom('No participant in group message')
128
+ throw new Boom("No participant in group message");
101
129
  }
102
- const isParticipantMe = isMe(participant)
103
- if (WABinary_1.isJidStatusBroadcast(from)) {
104
- msg_type = isParticipantMe ? 'direct_peer_status' : 'other_status'
130
+ const isParticipantMe = isMe(participant);
131
+ if (isJidStatusBroadcast(from)) {
132
+ msgType = isParticipantMe ? "direct_peer_status" : "other_status";
133
+ } else {
134
+ msgType = isParticipantMe ? "peer_broadcast" : "other_broadcast";
105
135
  }
106
- else {
107
- msg_type = isParticipantMe ? 'peer_broadcast' : 'other_broadcast'
136
+ fromMe = isParticipantMe;
137
+ chatId = from;
138
+ author = participant;
139
+ } else if (isJidNewsletter(from)) {
140
+ msgType = "newsletter";
141
+ chatId = from;
142
+ author = from;
143
+ if (isMe(from) || isMeLid(from)) {
144
+ fromMe = true;
108
145
  }
109
- chat_id = from
110
- author = participant
111
- } else if (WABinary_1.isJidNewsletter(from)) {
112
- msg_type = 'newsletter'
113
- chat_id = from
114
- author = from
115
146
  } else {
116
- throw new boom_1.Boom('Unknown message type', { data: stanza })
147
+ throw new Boom("Unknown message type", { data: stanza });
117
148
  }
118
- // FIX: untuk private chat (isJidUser), participant === from (bukan undefined),
119
- // sehingga fallback ke stanza.attrs.from tidak diperlukan dan bisa menyebabkan
120
- // fromMe=true saat pesan dari orang lain di kondisi edge case LID.
121
- // Kita batasi fallback hanya untuk group (di mana participant memang bisa undefined).
122
- const fromMe = WABinary_1.isJidNewsletter(from)
123
- ? !!stanza.attrs?.is_sender
124
- : WABinary_1.isLidUser(from)
125
- ? isMeLid(participant != null ? participant : stanza.attrs.from)
126
- : (WABinary_1.isJidGroup(from) || WABinary_1.isJidBroadcast(from))
127
- ? isMe(participant != null ? participant : stanza.attrs.from)
128
- : isMe(from)
129
- const pushname = stanza?.attrs?.notify
149
+ const pushname = stanza?.attrs?.notify;
130
150
  const key = {
131
- remoteJid: chat_id,
132
- fromMe,
151
+ remoteJid: chatId,
152
+ remoteJidAlt: !isJidGroup(chatId) ? addressingContext.senderAlt : undefined,
153
+ fromMe: fromMe,
133
154
  id: msgId,
134
- participant: WABinary_1.jidNormalizedUser(participant),
135
- participant_lid: WABinary_1.jidNormalizedUser(participant_lid),
136
- }
155
+ participant: participant,
156
+ participantAlt: isJidGroup(chatId) ? addressingContext.senderAlt : undefined,
157
+ addressingMode: addressingContext.addressingMode,
158
+ ...(msgType === "newsletter" && stanza.attrs.server_id
159
+ ? { server_id: stanza.attrs.server_id }
160
+ : {}),
161
+ };
137
162
  const fullMessage = {
138
- key,
163
+ key: key,
164
+ category: stanza.attrs.category,
139
165
  messageTimestamp: +stanza.attrs.t,
140
166
  pushName: pushname,
141
- broadcast: WABinary_1.isJidBroadcast(from),
142
- newsletter: WABinary_1.isJidNewsletter(from)
143
- }
144
- if (msg_type === 'newsletter') {
145
- fullMessage.newsletter_server_id = +stanza.attrs?.server_id
146
- }
167
+ platform: getDevice(key.id),
168
+ broadcast: isJidBroadcast(from),
169
+ newsletter: isJidNewsletter(from),
170
+ };
147
171
  if (key.fromMe) {
148
- fullMessage.status = WAProto_1.proto.WebMessageInfo.Status.SERVER_ACK
149
- }
150
- if (!key.fromMe) {
151
- fullMessage.platform = messages_1.getDevice(key.id)
172
+ fullMessage.status = proto.WebMessageInfo.Status.SERVER_ACK;
152
173
  }
153
174
  return {
154
- fullMessage,
155
- author,
156
- sender: msg_type === 'chat' ? author : chat_id
157
- }
175
+ fullMessage: fullMessage,
176
+ author: author,
177
+ sender: msgType === "chat" ? author : chatId,
178
+ };
158
179
  }
159
-
160
- const getDecryptionJid = async (sender, repository) => {
161
- if (WABinary_1.isLidUser(sender)) {
162
- return sender
163
- }
164
- const mapped = await repository.lidMapping.getLIDForPN(sender)
165
- if (!mapped) {
166
- return sender
167
- }
168
- // FIX: pontalabs gak punya migrateSession (beda dari levvleys) yang
169
- // mindahin sesi Signal dari address PN ke address LID begitu mapping
170
- // disimpan. Jadi mapping doang gak jamin ada sesi beneran di address LID
171
- // itu -- kalau dipaksa pakai, decrypt gagal "No session record" walau
172
- // pesannya normal (msg, bukan pkmsg). Ini yang bikin pesan self-chat/PN
173
- // ilang total: begitu mapping ke-cache, semua decrypt berikutnya diarahin
174
- // ke LID yang sesinya gak pernah ada. Makanya sebelum pakai LID, pastikan
175
- // dulu ada sesi aktif di situ; kalau enggak, tetep pakai address asli (PN).
176
- try {
177
- const lidSession = await repository.validateSession(mapped)
178
- if (lidSession.exists) {
179
- return mapped
180
- }
181
- } catch {
182
- // biarin jatuh ke fallback sender di bawah kalau validateSession error
183
- }
184
- return sender
185
- }
186
-
187
- // FIX: pontalabs sebelumnya gak pernah menyimpan mapping LID<->PN saat pesan
188
- // masuk (levvleys punya storeMappingFromEnvelope, di sini gak ada). Akibatnya
189
- // untuk kontak yang pakai addressing LID, getDecryptionJid bisa gagal nemuin
190
- // sesi yang benar secara intermiten (tergantung cache mapping ada atau belum),
191
- // bikin decrypt gagal -> pesan jadi CIPHERTEXT -> gak pernah nyampe ke bot.
192
- const extractSenderAlt = (stanza) => {
193
- const sender = stanza.attrs.participant || stanza.attrs.from
194
- const addressingMode = stanza.attrs.addressing_mode || (sender?.endsWith('lid') ? 'lid' : 'pn')
195
- if (addressingMode === 'lid') {
196
- return stanza.attrs.participant_pn || stanza.attrs.sender_pn || stanza.attrs.peer_recipient_pn
197
- }
198
- return stanza.attrs.participant_lid || stanza.attrs.sender_lid || stanza.attrs.peer_recipient_lid
199
- }
200
-
201
- const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJid, logger) => {
202
- const senderAlt = extractSenderAlt(stanza)
203
- if (senderAlt && WABinary_1.isLidUser(senderAlt) && WABinary_1.isJidUser(sender) && decryptionJid === sender) {
204
- try {
205
- await repository.lidMapping.storeLIDPNMappings([{ lid: senderAlt, pn: sender }])
206
- if (typeof repository.migrateSession === 'function') {
207
- await repository.migrateSession(sender, senderAlt)
208
- }
209
- logger.debug({ sender, senderAlt }, 'Stored LID mapping from envelope')
210
- } catch (error) {
211
- logger.warn({ sender, senderAlt, error }, 'Failed to store LID mapping')
212
- }
213
- }
214
- }
215
-
216
180
  const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
217
- const { fullMessage, author, sender } = decodeMessageNode(stanza, meId, meLid)
181
+ const {
182
+ fullMessage: fullMessage,
183
+ author: author,
184
+ sender: sender,
185
+ } = decodeMessageNode(stanza, meId, meLid);
218
186
  return {
219
- fullMessage,
187
+ fullMessage: fullMessage,
220
188
  category: stanza.attrs.category,
221
- author,
189
+ author: author,
222
190
  async decrypt() {
223
- let decryptables = 0
191
+ let decryptables = 0;
224
192
  if (Array.isArray(stanza.content)) {
225
- // FIX: proses node non-skmsg (msg/pkmsg/plaintext) LEBIH DULU sebelum node
226
- // skmsg. Root cause "bot diam/nunggu" pas ada member baru join grup lalu
227
- // langsung kirim pesan: satu stanza berisi 2 node <enc> - satu tipe
228
- // pkmsg/msg (isinya SenderKeyDistributionMessage buat kamu) dan satu lagi
229
- // tipe skmsg (isi pesan asli, dienkripsi pakai sender-key grup). Urutan
230
- // array stanza.content dari server TIDAK dijamin naruh pkmsg/msg duluan.
231
- // Kalau skmsg kebetulan diproses duluan, sender-key belum ada di store ->
232
- // decryptGroupMessage() gagal "No SenderKeyRecord found" -> pesan pertama
233
- // dari member baru selalu gagal decrypt & jadi stub CIPHERTEXT, padahal
234
- // SKDM-nya baru "sampai" sepersekian detik kemudian di iterasi berikutnya.
235
- // Reorder di sini (stable, gak ubah urutan relatif node lain seperti
236
- // verified_name/unavailable) supaya skmsg selalu diproses PALING TERAKHIR,
237
- // setelah semua kemungkinan SKDM sudah didaftarkan ke sender-key store.
238
- const orderedContent = [
239
- ...stanza.content.filter(({ tag, attrs }) => !(tag === 'enc' && attrs.type === 'skmsg')),
240
- ...stanza.content.filter(({ tag, attrs }) => tag === 'enc' && attrs.type === 'skmsg')
241
- ]
242
- for (const { tag, attrs, content } of orderedContent) {
243
- if (tag === 'verified_name' && content instanceof Uint8Array) {
244
- const cert = WAProto_1.proto.VerifiedNameCertificate.decode(content)
245
- const details = WAProto_1.proto.VerifiedNameCertificate.Details.decode(cert.details)
246
- fullMessage.verifiedBizName = details.verifiedName
193
+ for (const { tag: tag, attrs: attrs, content: content } of stanza.content) {
194
+ if (tag === "verified_name" && content instanceof Uint8Array) {
195
+ const cert = proto.VerifiedNameCertificate.decode(content);
196
+ const details = proto.VerifiedNameCertificate.Details.decode(cert.details);
197
+ fullMessage.verifiedBizName = details.verifiedName;
247
198
  }
248
- if (tag === 'unavailable' && attrs.type === 'view_once') {
199
+ if (tag === "unavailable" && attrs.type === "view_once") {
249
200
  fullMessage.key.isViewOnce = true;
250
201
  }
251
- if (attrs.count && tag === 'enc') {
252
- fullMessage.retryCount = Number(attrs.count)
202
+ if (attrs.count && tag === "enc") {
203
+ fullMessage.retryCount = Number(attrs.count);
253
204
  }
254
- if (tag !== 'enc' && tag !== 'plaintext') {
255
- continue
205
+ if (tag !== "enc" && tag !== "plaintext") {
206
+ continue;
256
207
  }
257
208
  if (!(content instanceof Uint8Array)) {
258
- continue
209
+ continue;
210
+ }
211
+ decryptables += 1;
212
+ let msgBuffer;
213
+ const decryptionJid = await getDecryptionJid(author, repository);
214
+ if (tag !== "plaintext") {
215
+ await storeMappingFromEnvelope(
216
+ stanza,
217
+ author,
218
+ repository,
219
+ decryptionJid,
220
+ logger
221
+ );
259
222
  }
260
- decryptables += 1
261
- let msgBuffer
262
223
  try {
263
- const e2eType = tag === 'plaintext' ? 'plaintext' : attrs.type
224
+ const e2eType = tag === "plaintext" ? "plaintext" : attrs.type;
264
225
  switch (e2eType) {
265
- case 'skmsg':
226
+ case "skmsg":
266
227
  msgBuffer = await repository.decryptGroupMessage({
267
228
  group: sender,
268
229
  authorJid: author,
269
- msg: content
270
- })
271
- break
272
- case 'pkmsg':
273
- case 'msg': {
274
- const decryptionJid = await getDecryptionJid(author, repository)
275
- await storeMappingFromEnvelope(stanza, author, repository, decryptionJid, logger)
230
+ msg: content,
231
+ });
232
+ break;
233
+ case "pkmsg":
234
+ case "msg":
276
235
  msgBuffer = await repository.decryptMessage({
277
236
  jid: decryptionJid,
278
237
  type: e2eType,
279
- ciphertext: content
280
- })
281
- break
282
- }
283
- case 'plaintext':
284
- msgBuffer = content
285
- break
238
+ ciphertext: content,
239
+ });
240
+ break;
241
+ case "plaintext":
242
+ msgBuffer = content;
243
+ break;
286
244
  default:
287
- throw new Error(`Unknown e2e type: ${e2eType}`)
245
+ throw new Error(`Unknown e2e type: ${e2eType}`);
288
246
  }
289
- let msg = WAProto_1.proto.Message.decode(e2eType !== 'plaintext' ? generics_1.unpadRandomMax16(msgBuffer) : msgBuffer)
290
- msg = msg.deviceSentMessage?.message || msg
247
+ let msg = proto.Message.decode(
248
+ e2eType !== "plaintext" ? unpadRandomMax16(msgBuffer) : msgBuffer
249
+ );
250
+ msg = msg.deviceSentMessage?.message || msg;
291
251
  if (msg.senderKeyDistributionMessage) {
292
252
  try {
293
253
  await repository.processSenderKeyDistributionMessage({
294
254
  authorJid: author,
295
- item: msg.senderKeyDistributionMessage
296
- })
255
+ item: msg.senderKeyDistributionMessage,
256
+ });
297
257
  } catch (err) {
298
- logger.error({ key: fullMessage.key, err }, 'failed to decrypt message')
258
+ logger.error(
259
+ { key: fullMessage.key, err: err },
260
+ "failed to process sender key distribution message"
261
+ );
299
262
  }
300
263
  }
301
264
  if (fullMessage.message) {
302
- Object.assign(fullMessage.message, msg)
265
+ Object.assign(fullMessage.message, msg);
303
266
  } else {
304
- fullMessage.message = msg
305
- }
306
- if (WABinary_1.isJidGroup(sender)) {
307
- const mtype = getTypeMessage(fullMessage.message)
308
- const message = fullMessage.message?.[mtype]
309
- const contextInfo = message?.contextInfo
310
- const mentionedJid = contextInfo?.mentionedJid
311
- const processMessageLIDs = async (msgObj, msgType) => {
312
- if (!msgObj?.contextInfo) return false
313
- const contextInfo = msgObj.contextInfo
314
- const mentionedJid = contextInfo.mentionedJid
315
- let needsUpdate = false
316
- if (Array.isArray(mentionedJid) && mentionedJid.length > 0) {
317
- const metadata = await global.groupMetadataCache(sender)
318
- const updatedMentionedJid = []
319
- for (const mentionedLid of mentionedJid) {
320
- if (typeof mentionedLid === "string" && mentionedLid.endsWith('@lid')) {
321
- const found = metadata.participants.find(p => p.lid === mentionedLid)
322
- if (found) {
323
- updatedMentionedJid.push(found.id)
324
- if (msgObj.text) {
325
- msgObj.text = msgObj.text.replace(new RegExp(`@${mentionedLid.split("@")[0]}`, "g"), `@${found.id.split("@")[0]}`);
326
- } else if (msgObj.caption) {
327
- msgObj.caption = msgObj.caption.replace(new RegExp(`@${mentionedLid.split("@")[0]}`, "g"), `@${found.id.split("@")[0]}`);
328
- }
329
- } else {
330
- const lid = WABinary_1.jidNormalizedUser(mentionedLid)
331
- const mentioned_jid = await repository.lidMapping.getPNForLID(mentionedLid)
332
- if (mentioned_jid) {
333
- const pn = WABinary_1.jidNormalizedUser(mentioned_jid)
334
- await repository.lidMapping.storeLIDPNMappings([{ lid, pn }])
335
- updatedMentionedJid.push(pn)
336
- if (msgObj.text) {
337
- msgObj.text = msgObj.text.replace(new RegExp(`@${mentionedLid.split("@")[0]}`, "g"), `@${pn.split("@")[0]}`);
338
- } else if (msgObj.caption) {
339
- msgObj.caption = msgObj.caption.replace(new RegExp(`@${mentionedLid.split("@")[0]}`, "g"), `@${pn.split("@")[0]}`);
340
- }
341
- } else {
342
- updatedMentionedJid.push(mentionedLid)
343
- }
344
- }
345
- needsUpdate = true
346
- } else {
347
- updatedMentionedJid.push(mentionedLid)
348
- }
349
- }
350
- if (needsUpdate) {
351
- msgObj.contextInfo.mentionedJid = updatedMentionedJid
352
- }
353
- }
354
- return needsUpdate
355
- }
356
- const quotedMessage = contextInfo?.quotedMessage
357
- if (quotedMessage) {
358
- const quotedMtype = getTypeMessage(quotedMessage)
359
- const quotedMsgObj = quotedMessage[quotedMtype]
360
- if (quotedMsgObj?.contextInfo) {
361
- await processMessageLIDs(quotedMsgObj, quotedMtype)
362
- }
363
- }
267
+ fullMessage.message = msg;
364
268
  }
365
269
  } catch (err) {
366
270
  const errorContext = {
367
271
  key: fullMessage.key,
368
- err,
369
- messageType: tag === 'plaintext' ? 'plaintext' : attrs.type,
370
- sender,
371
- author,
372
- isSessionRecordError: isSessionRecordError(err)
373
- }
374
- logger.error(errorContext, 'failed to decrypt message')
375
- fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT
376
- fullMessage.messageStubParameters = [err.message.toString()]
272
+ err: err,
273
+ messageType: tag === "plaintext" ? "plaintext" : attrs.type,
274
+ sender: sender,
275
+ author: author,
276
+ isSessionRecordError: isSessionRecordError(err),
277
+ };
278
+ logger.error(errorContext, "failed to decrypt message");
279
+ fullMessage.messageStubType = proto.WebMessageInfo.StubType.CIPHERTEXT;
280
+ fullMessage.messageStubParameters = [err.message.toString()];
377
281
  }
378
282
  }
379
283
  }
380
-
381
284
  if (!decryptables && !fullMessage.key?.isViewOnce) {
382
- fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT
383
- fullMessage.messageStubParameters = [NO_MESSAGE_FOUND_ERROR_TEXT]
285
+ fullMessage.messageStubType = proto.WebMessageInfo.StubType.CIPHERTEXT;
286
+ fullMessage.messageStubParameters = [NO_MESSAGE_FOUND_ERROR_TEXT];
384
287
  }
385
- }
386
- }
387
- }
388
-
288
+ },
289
+ };
290
+ };
389
291
  function isSessionRecordError(error) {
390
- const errorMessage = error?.message || error?.toString() || ''
391
- return DECRYPTION_RETRY_CONFIG.sessionRecordErrors.some(errorPattern => errorMessage.includes(errorPattern))
292
+ const errorMessage = error?.message || error?.toString() || "";
293
+ return DECRYPTION_RETRY_CONFIG.sessionRecordErrors.some((errorPattern) =>
294
+ errorMessage.includes(errorPattern)
295
+ );
392
296
  }
393
-
394
297
  module.exports = {
395
- NACK_REASONS,
396
- decodeMessageNode,
397
- decryptMessageNode,
398
- MISSING_KEYS_ERROR_TEXT,
399
- DECRYPTION_RETRY_CONFIG,
400
- NO_MESSAGE_FOUND_ERROR_TEXT
401
- }
298
+ NACK_REASONS: NACK_REASONS,
299
+ decodeMessageNode: decodeMessageNode,
300
+ decryptMessageNode: decryptMessageNode,
301
+ extractAddressingContext: extractAddressingContext,
302
+ MISSING_KEYS_ERROR_TEXT: MISSING_KEYS_ERROR_TEXT,
303
+ DECRYPTION_RETRY_CONFIG: DECRYPTION_RETRY_CONFIG,
304
+ NO_MESSAGE_FOUND_ERROR_TEXT: NO_MESSAGE_FOUND_ERROR_TEXT,
305
+ };