@pontalabs/baileys 1.0.6 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +839 -267
  3. package/WAProto/GenerateStatics.sh +4 -3
  4. package/WAProto/WAProto.proto +511 -1215
  5. package/WAProto/index.d.ts +55 -14017
  6. package/WAProto/index.js +29 -97689
  7. package/lib/Defaults/index.d.ts +74 -72
  8. package/lib/Defaults/index.js +108 -94
  9. package/lib/Signal/Group/ciphertext-message.d.ts +7 -8
  10. package/lib/Signal/Group/ciphertext-message.js +16 -9
  11. package/lib/Signal/Group/group-session-builder.d.ts +13 -11
  12. package/lib/Signal/Group/group-session-builder.js +61 -19
  13. package/lib/Signal/Group/group_cipher.d.ts +16 -14
  14. package/lib/Signal/Group/group_cipher.js +70 -41
  15. package/lib/Signal/Group/index.d.ts +11 -12
  16. package/lib/Signal/Group/index.js +61 -12
  17. package/lib/Signal/Group/keyhelper.d.ts +14 -9
  18. package/lib/Signal/Group/keyhelper.js +58 -10
  19. package/lib/Signal/Group/sender-chain-key.d.ts +13 -13
  20. package/lib/Signal/Group/sender-chain-key.js +34 -13
  21. package/lib/Signal/Group/sender-key-distribution-message.d.ts +16 -16
  22. package/lib/Signal/Group/sender-key-distribution-message.js +36 -28
  23. package/lib/Signal/Group/sender-key-message.d.ts +18 -18
  24. package/lib/Signal/Group/sender-key-message.js +45 -38
  25. package/lib/Signal/Group/sender-key-name.d.ts +15 -14
  26. package/lib/Signal/Group/sender-key-name.js +31 -20
  27. package/lib/Signal/Group/sender-key-record.d.ts +25 -24
  28. package/lib/Signal/Group/sender-key-record.js +35 -18
  29. package/lib/Signal/Group/sender-key-state.d.ts +34 -29
  30. package/lib/Signal/Group/sender-key-state.js +100 -37
  31. package/lib/Signal/Group/sender-message-key.d.ts +10 -11
  32. package/lib/Signal/Group/sender-message-key.js +22 -15
  33. package/lib/Signal/libsignal.d.ts +8 -5
  34. package/lib/Signal/libsignal.js +142 -288
  35. package/lib/Signal/lid-mapping.d.ts +28 -23
  36. package/lib/Signal/lid-mapping.js +184 -277
  37. package/lib/Socket/Client/index.d.ts +2 -3
  38. package/lib/Socket/Client/index.js +22 -3
  39. package/lib/Socket/Client/types.d.ts +15 -15
  40. package/lib/Socket/Client/types.js +15 -8
  41. package/lib/Socket/Client/websocket.d.ts +12 -12
  42. package/lib/Socket/Client/websocket.js +37 -29
  43. package/lib/Socket/business.d.ts +178 -208
  44. package/lib/Socket/business.js +127 -91
  45. package/lib/Socket/chats.d.ts +93 -120
  46. package/lib/Socket/chats.js +652 -727
  47. package/lib/Socket/community.js +10 -2
  48. package/lib/Socket/groups.d.ts +111 -143
  49. package/lib/Socket/groups.js +186 -165
  50. package/lib/Socket/index.d.ts +183 -252
  51. package/lib/Socket/index.js +18 -38
  52. package/lib/Socket/messages-recv.d.ts +167 -196
  53. package/lib/Socket/messages-recv.js +1567 -1443
  54. package/lib/Socket/messages-send.d.ts +158 -192
  55. package/lib/Socket/messages-send.js +1208 -1102
  56. package/lib/Socket/newsletter.d.ts +138 -163
  57. package/lib/Socket/newsletter.js +249 -153
  58. package/lib/Socket/socket.d.ts +36 -50
  59. package/lib/Socket/socket.js +820 -749
  60. package/lib/Store/index.d.ts +4 -4
  61. package/lib/Store/index.js +24 -4
  62. package/lib/Store/make-in-memory-store.d.ts +104 -44
  63. package/lib/Store/make-in-memory-store.js +213 -199
  64. package/lib/Store/make-ordered-dictionary.d.ts +12 -13
  65. package/lib/Store/make-ordered-dictionary.js +45 -38
  66. package/lib/Store/object-repository.d.ts +10 -11
  67. package/lib/Store/object-repository.js +16 -9
  68. package/lib/Types/Auth.d.ts +97 -93
  69. package/lib/Types/Auth.js +3 -2
  70. package/lib/Types/Bussines.js +3 -2
  71. package/lib/Types/Call.d.ts +13 -14
  72. package/lib/Types/Call.js +3 -2
  73. package/lib/Types/Chat.d.ts +97 -78
  74. package/lib/Types/Chat.js +9 -8
  75. package/lib/Types/Contact.d.ts +9 -12
  76. package/lib/Types/Contact.js +3 -2
  77. package/lib/Types/Events.d.ts +176 -206
  78. package/lib/Types/Events.js +3 -2
  79. package/lib/Types/GroupMetadata.d.ts +48 -53
  80. package/lib/Types/GroupMetadata.js +3 -2
  81. package/lib/Types/Label.d.ts +14 -13
  82. package/lib/Types/Label.js +30 -24
  83. package/lib/Types/LabelAssociation.d.ts +20 -15
  84. package/lib/Types/LabelAssociation.js +12 -6
  85. package/lib/Types/Message.d.ts +412 -248
  86. package/lib/Types/Message.js +19 -17
  87. package/lib/Types/Product.d.ts +71 -58
  88. package/lib/Types/Product.js +3 -2
  89. package/lib/Types/Signal.d.ts +82 -71
  90. package/lib/Types/Signal.js +3 -2
  91. package/lib/Types/Socket.d.ts +81 -76
  92. package/lib/Types/Socket.js +3 -3
  93. package/lib/Types/State.d.ts +19 -75
  94. package/lib/Types/State.js +14 -56
  95. package/lib/Types/USync.d.ts +8 -8
  96. package/lib/Types/USync.js +3 -2
  97. package/lib/Types/index.d.ts +62 -47
  98. package/lib/Types/index.js +50 -26
  99. package/lib/Utils/auth-utils.d.ts +10 -13
  100. package/lib/Utils/auth-utils.js +472 -213
  101. package/lib/Utils/business.d.ts +20 -14
  102. package/lib/Utils/business.js +134 -110
  103. package/lib/Utils/chat-utils.d.ts +70 -88
  104. package/lib/Utils/chat-utils.js +403 -466
  105. package/lib/Utils/crypto.d.ts +46 -27
  106. package/lib/Utils/crypto.js +188 -117
  107. package/lib/Utils/decode-wa-message.d.ts +45 -58
  108. package/lib/Utils/decode-wa-message.js +311 -212
  109. package/lib/Utils/event-buffer.d.ts +17 -14
  110. package/lib/Utils/event-buffer.js +296 -321
  111. package/lib/Utils/generics.d.ts +92 -66
  112. package/lib/Utils/generics.js +436 -270
  113. package/lib/Utils/history.d.ts +23 -24
  114. package/lib/Utils/history.js +76 -106
  115. package/lib/Utils/index.d.ts +21 -24
  116. package/lib/Utils/index.js +41 -24
  117. package/lib/Utils/link-preview.d.ts +14 -12
  118. package/lib/Utils/link-preview.js +75 -40
  119. package/lib/Utils/logger.d.ts +11 -10
  120. package/lib/Utils/logger.js +7 -3
  121. package/lib/Utils/lt-hash.d.ts +14 -8
  122. package/lib/Utils/lt-hash.js +53 -3
  123. package/lib/Utils/make-mutex.d.ts +7 -7
  124. package/lib/Utils/make-mutex.js +44 -28
  125. package/lib/Utils/message-retry-manager.d.ts +88 -115
  126. package/lib/Utils/message-retry-manager.js +160 -265
  127. package/lib/Utils/messages-media.d.ts +107 -105
  128. package/lib/Utils/messages-media.js +619 -548
  129. package/lib/Utils/messages.d.ts +66 -52
  130. package/lib/Utils/messages.js +1558 -1730
  131. package/lib/Utils/noise-handler.d.ts +18 -18
  132. package/lib/Utils/noise-handler.js +130 -176
  133. package/lib/Utils/process-message.d.ts +32 -43
  134. package/lib/Utils/process-message.js +282 -484
  135. package/lib/Utils/rich-message-utils.js +724 -1220
  136. package/lib/Utils/signal.d.ts +32 -37
  137. package/lib/Utils/signal.js +105 -140
  138. package/lib/Utils/use-multi-file-auth-state.d.ts +5 -5
  139. package/lib/Utils/use-multi-file-auth-state.js +120 -70
  140. package/lib/Utils/use-single-file-auth-state.d.ts +13 -11
  141. package/lib/Utils/use-single-file-auth-state.js +66 -92
  142. package/lib/Utils/validate-connection.d.ts +13 -11
  143. package/lib/Utils/validate-connection.js +113 -128
  144. package/lib/WABinary/constants.d.ts +27 -25
  145. package/lib/WABinary/constants.js +1292 -1451
  146. package/lib/WABinary/decode.d.ts +9 -7
  147. package/lib/WABinary/decode.js +189 -163
  148. package/lib/WABinary/encode.d.ts +3 -3
  149. package/lib/WABinary/encode.js +155 -110
  150. package/lib/WABinary/generic-utils.d.ts +27 -14
  151. package/lib/WABinary/generic-utils.js +105 -177
  152. package/lib/WABinary/index.d.ts +5 -6
  153. package/lib/WABinary/index.js +25 -6
  154. package/lib/WABinary/jid-utils.d.ts +54 -41
  155. package/lib/WABinary/jid-utils.js +152 -83
  156. package/lib/WABinary/types.d.ts +13 -10
  157. package/lib/WABinary/types.js +3 -2
  158. package/lib/WAM/BinaryInfo.d.ts +15 -8
  159. package/lib/WAM/BinaryInfo.js +14 -7
  160. package/lib/WAM/constants.d.ts +37 -30
  161. package/lib/WAM/constants.js +11983 -19465
  162. package/lib/WAM/encode.d.ts +3 -3
  163. package/lib/WAM/encode.js +109 -95
  164. package/lib/WAM/index.d.ts +3 -4
  165. package/lib/WAM/index.js +23 -4
  166. package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +9 -9
  167. package/lib/WAUSync/Protocols/USyncContactProtocol.js +21 -37
  168. package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +22 -19
  169. package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +26 -18
  170. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -11
  171. package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +20 -12
  172. package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -11
  173. package/lib/WAUSync/Protocols/USyncStatusProtocol.js +24 -16
  174. package/lib/WAUSync/Protocols/index.d.ts +6 -6
  175. package/lib/WAUSync/Protocols/index.js +26 -6
  176. package/lib/WAUSync/USyncQuery.d.ts +28 -27
  177. package/lib/WAUSync/USyncQuery.js +62 -68
  178. package/lib/WAUSync/USyncUser.d.ts +10 -15
  179. package/lib/WAUSync/USyncUser.js +19 -20
  180. package/lib/WAUSync/index.d.ts +3 -4
  181. package/lib/WAUSync/index.js +23 -4
  182. package/lib/index.d.ts +12 -11
  183. package/lib/index.js +39 -12
  184. package/package.json +43 -87
  185. package/engine-requirements.js +0 -10
@@ -1,42 +1,24 @@
1
- import { Boom } from '@hapi/boom';
2
- import { proto } from '../../WAProto/index.js';
3
- import { areJidsSameUser, isHostedLidUser, isHostedPnUser, isJidBroadcast, isJidGroup, isJidMetaAI, isJidNewsletter, isJidStatusBroadcast, isLidUser, isPnUser
4
- // transferDevice
5
- } from '../WABinary/index.js';
6
- import { unpadRandomMax16 } from './generics.js';
7
- export const getDecryptionJid = async (sender, repository) => {
8
- if (isLidUser(sender) || isHostedLidUser(sender)) {
9
- return sender;
10
- }
11
- const mapped = await repository.lidMapping.getLIDForPN(sender);
12
- return mapped || sender;
13
- };
14
- const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJid, logger) => {
15
- // TODO: Handle hosted IDs
16
- const { senderAlt } = extractAddressingContext(stanza);
17
- if (senderAlt && isLidUser(senderAlt) && isPnUser(sender) && decryptionJid === sender) {
18
- try {
19
- await repository.lidMapping.storeLIDPNMappings([{ lid: senderAlt, pn: sender }]);
20
- await repository.migrateSession(sender, senderAlt);
21
- logger.debug({ sender, senderAlt }, 'Stored LID mapping from envelope');
22
- }
23
- catch (error) {
24
- logger.warn({ sender, senderAlt, error }, 'Failed to store LID mapping');
25
- }
26
- }
27
- };
28
- export const NO_MESSAGE_FOUND_ERROR_TEXT = 'Message absent from node';
29
- export const MISSING_KEYS_ERROR_TEXT = 'Key used already or never filled';
30
- export const ACCOUNT_RESTRICTED_TEXT = 'Your account has been restricted';
31
- // Retry configuration for failed decryption
32
- export const DECRYPTION_RETRY_CONFIG = {
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
+
15
+ const DECRYPTION_RETRY_CONFIG = {
33
16
  maxRetries: 3,
34
17
  baseDelayMs: 100,
35
18
  sessionRecordErrors: ['No session record', 'SessionError: No session record']
36
- };
37
- /** NACK reason codes we send to the server (client → server) */
38
- export const NACK_REASONS = {
39
- SenderReachoutTimelocked: 463,
19
+ }
20
+
21
+ const NACK_REASONS = {
40
22
  ParsingError: 487,
41
23
  UnrecognizedStanza: 488,
42
24
  UnrecognizedStanzaClass: 489,
@@ -50,235 +32,346 @@ export const NACK_REASONS = {
50
32
  UnsupportedAdminRevoke: 550,
51
33
  UnsupportedLIDGroup: 551,
52
34
  DBOperationFailed: 552
53
- };
54
- /**
55
- * Server-side error codes returned in ack stanzas (server → client) that we
56
- * currently have dedicated handlers for. Extend as more handlers are added.
57
- * Distinct from the client-side NackReason enum (WAWebCreateNackFromStanza).
58
- */
59
- export const SERVER_ERROR_CODES = {
60
- /**
61
- * 1:1 message missing privacy token (tctoken). Usually means the account is
62
- * restricted: WhatsApp blocks starting new chats but preserves existing ones,
63
- * since established chats already carry a tctoken.
64
- */
65
- MessageAccountRestriction: '463',
66
- /** Stanza validation failure (SMAX_INVALID) — likely stale device session */
67
- SmaxInvalid: '479'
68
- };
69
- export const extractAddressingContext = (stanza) => {
70
- let senderAlt;
71
- let recipientAlt;
72
- const sender = stanza.attrs.participant || stanza.attrs.from;
73
- const addressingMode = stanza.attrs.addressing_mode || (sender?.endsWith('lid') ? 'lid' : 'pn');
74
- if (addressingMode === 'lid') {
75
- // Message is LID-addressed: sender is LID, extract corresponding PN
76
- // without device data
77
- senderAlt = stanza.attrs.participant_pn || stanza.attrs.sender_pn || stanza.attrs.peer_recipient_pn;
78
- recipientAlt = stanza.attrs.recipient_pn;
79
- // with device data
80
- //if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
81
- }
82
- else {
83
- // Message is PN-addressed: sender is PN, extract corresponding LID
84
- // without device data
85
- senderAlt = stanza.attrs.participant_lid || stanza.attrs.sender_lid || stanza.attrs.peer_recipient_lid;
86
- recipientAlt = stanza.attrs.recipient_lid;
87
- //with device data
88
- //if (sender && senderAlt) senderAlt = transferDevice(sender, senderAlt)
89
- }
90
- return {
91
- addressingMode,
92
- senderAlt,
93
- recipientAlt
94
- };
95
- };
96
- /**
97
- * Decode the received node as a message.
98
- * @note this will only parse the message, not decrypt it
99
- */
100
- export function decodeMessageNode(stanza, meId, meLid) {
101
- let msgType;
102
- let chatId;
103
- let author;
104
- let fromMe = false;
105
- const msgId = stanza.attrs.id;
106
- const from = stanza.attrs.from;
107
- const participant = stanza.attrs.participant;
108
- const recipient = stanza.attrs.recipient;
109
- if (!msgId) {
110
- throw new Boom('Invalid message stanza: missing id attribute', { data: stanza });
111
- }
112
- if (!from) {
113
- throw new Boom('Invalid message stanza: missing from attribute', { data: stanza });
114
- }
115
- const addressingContext = extractAddressingContext(stanza);
116
- const isMe = (jid) => areJidsSameUser(jid, meId);
117
- const isMeLid = (jid) => areJidsSameUser(jid, meLid);
118
- if (isPnUser(from) || isLidUser(from) || isHostedLidUser(from) || isHostedPnUser(from)) {
119
- if (recipient && !isJidMetaAI(recipient)) {
120
- if (!isMe(from) && !isMeLid(from)) {
121
- throw new Boom('receipient present, but msg not from me', { data: stanza });
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
+
43
+ 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 })
122
58
  }
123
- if (isMe(from) || isMeLid(from)) {
124
- fromMe = true;
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 })
125
70
  }
126
- chatId = recipient;
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
127
75
  }
128
76
  else {
129
- chatId = from;
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
130
83
  }
131
- msgType = 'chat';
132
- author = from;
133
- }
134
- else if (isJidGroup(from)) {
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)) {
135
92
  if (!participant) {
136
- throw new Boom('No participant in group message');
137
- }
138
- if (isMe(participant) || isMeLid(participant)) {
139
- fromMe = true;
93
+ throw new boom_1.Boom('No participant in group message')
140
94
  }
141
- msgType = 'group';
142
- author = participant;
143
- chatId = from;
144
- }
145
- else if (isJidBroadcast(from)) {
95
+ msg_type = 'group'
96
+ author = participant
97
+ chat_id = from
98
+ } else if (WABinary_1.isJidBroadcast(from)) {
146
99
  if (!participant) {
147
- throw new Boom('No participant in group message');
100
+ throw new boom_1.Boom('No participant in group message')
148
101
  }
149
- const isParticipantMe = isMe(participant);
150
- if (isJidStatusBroadcast(from)) {
151
- msgType = isParticipantMe ? 'direct_peer_status' : 'other_status';
102
+ const isParticipantMe = isMe(participant)
103
+ if (WABinary_1.isJidStatusBroadcast(from)) {
104
+ msg_type = isParticipantMe ? 'direct_peer_status' : 'other_status'
152
105
  }
153
106
  else {
154
- msgType = isParticipantMe ? 'peer_broadcast' : 'other_broadcast';
107
+ msg_type = isParticipantMe ? 'peer_broadcast' : 'other_broadcast'
155
108
  }
156
- fromMe = isParticipantMe;
157
- chatId = from;
158
- author = participant;
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
+ } else {
116
+ throw new boom_1.Boom('Unknown message type', { data: stanza })
159
117
  }
160
- else if (isJidNewsletter(from)) {
161
- msgType = 'newsletter';
162
- chatId = from;
163
- author = from;
164
- if (isMe(from) || isMeLid(from)) {
165
- fromMe = true;
166
- }
167
- }
168
- else {
169
- throw new Boom('Unknown message type', { data: stanza });
170
- }
171
- const pushname = stanza?.attrs?.notify;
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
130
+ // FIX: sebelumnya key pakai field ad-hoc "participant_lid" yang gak ada
131
+ // di tipe WAMessageKey (yang resmi dideklarasikan cuma participantAlt /
132
+ // remoteJidAlt), jadi konsumen yang ngikutin tipe gak bakal nemu field-nya.
133
+ // Sekarang dipetakan ke nama resmi, plus remoteJidAlt buat private chat
134
+ // yang datengnya dari address LID (chat_id di-resolve ke PN, jadi bentuk
135
+ // LID aslinya perlu disimpen di remoteJidAlt biar gak ilang).
172
136
  const key = {
173
- remoteJid: chatId,
174
- remoteJidAlt: !isJidGroup(chatId) ? addressingContext.senderAlt : undefined,
175
- remoteJidUsername: !isJidGroup(chatId)
176
- ? stanza.attrs.peer_recipient_username || stanza.attrs.recipient_username
137
+ remoteJid: chat_id,
138
+ remoteJidAlt: WABinary_1.isLidUser(from) && !WABinary_1.isLidUser(chat_id)
139
+ ? WABinary_1.jidNormalizedUser(from)
177
140
  : undefined,
178
141
  fromMe,
179
142
  id: msgId,
180
- participant,
181
- participantAlt: isJidGroup(chatId) ? addressingContext.senderAlt : undefined,
182
- participantUsername: stanza.attrs.participant ? stanza.attrs.participant_username : undefined,
183
- addressingMode: addressingContext.addressingMode,
184
- ...(msgType === 'newsletter' && stanza.attrs.server_id ? { server_id: stanza.attrs.server_id } : {})
185
- };
143
+ participant: WABinary_1.jidNormalizedUser(participant),
144
+ participantAlt: participant_lid ? WABinary_1.jidNormalizedUser(participant_lid) : undefined,
145
+ }
186
146
  const fullMessage = {
187
147
  key,
188
- category: stanza.attrs.category,
189
148
  messageTimestamp: +stanza.attrs.t,
190
149
  pushName: pushname,
191
- broadcast: isJidBroadcast(from)
192
- };
150
+ broadcast: WABinary_1.isJidBroadcast(from),
151
+ newsletter: WABinary_1.isJidNewsletter(from)
152
+ }
153
+ if (msg_type === 'newsletter') {
154
+ fullMessage.newsletter_server_id = +stanza.attrs?.server_id
155
+ }
193
156
  if (key.fromMe) {
194
- fullMessage.status = proto.WebMessageInfo.Status.SERVER_ACK;
157
+ fullMessage.status = WAProto_1.proto.WebMessageInfo.Status.SERVER_ACK
158
+ }
159
+ if (!key.fromMe) {
160
+ fullMessage.platform = messages_1.getDevice(key.id)
195
161
  }
196
162
  return {
197
163
  fullMessage,
198
164
  author,
199
- sender: msgType === 'chat' ? author : chatId
200
- };
165
+ sender: msg_type === 'chat' ? author : chat_id
166
+ }
167
+ }
168
+
169
+ const getDecryptionJid = async (sender, repository) => {
170
+ if (WABinary_1.isLidUser(sender)) {
171
+ return sender
172
+ }
173
+ const mapped = await repository.lidMapping.getLIDForPN(sender)
174
+ if (!mapped) {
175
+ return sender
176
+ }
177
+ // FIX: pontalabs gak punya migrateSession (beda dari levvleys) yang
178
+ // mindahin sesi Signal dari address PN ke address LID begitu mapping
179
+ // disimpan. Jadi mapping doang gak jamin ada sesi beneran di address LID
180
+ // itu -- kalau dipaksa pakai, decrypt gagal "No session record" walau
181
+ // pesannya normal (msg, bukan pkmsg). Ini yang bikin pesan self-chat/PN
182
+ // ilang total: begitu mapping ke-cache, semua decrypt berikutnya diarahin
183
+ // ke LID yang sesinya gak pernah ada. Makanya sebelum pakai LID, pastikan
184
+ // dulu ada sesi aktif di situ; kalau enggak, tetep pakai address asli (PN).
185
+ try {
186
+ const lidSession = await repository.validateSession(mapped)
187
+ if (lidSession.exists) {
188
+ return mapped
189
+ }
190
+ } catch {
191
+ // biarin jatuh ke fallback sender di bawah kalau validateSession error
192
+ }
193
+ return sender
194
+ }
195
+
196
+ // FIX: pontalabs sebelumnya gak pernah menyimpan mapping LID<->PN saat pesan
197
+ // masuk (levvleys punya storeMappingFromEnvelope, di sini gak ada). Akibatnya
198
+ // untuk kontak yang pakai addressing LID, getDecryptionJid bisa gagal nemuin
199
+ // sesi yang benar secara intermiten (tergantung cache mapping ada atau belum),
200
+ // bikin decrypt gagal -> pesan jadi CIPHERTEXT -> gak pernah nyampe ke bot.
201
+ const extractSenderAlt = (stanza) => {
202
+ const sender = stanza.attrs.participant || stanza.attrs.from
203
+ const addressingMode = stanza.attrs.addressing_mode || (sender?.endsWith('lid') ? 'lid' : 'pn')
204
+ if (addressingMode === 'lid') {
205
+ return stanza.attrs.participant_pn || stanza.attrs.sender_pn || stanza.attrs.peer_recipient_pn
206
+ }
207
+ return stanza.attrs.participant_lid || stanza.attrs.sender_lid || stanza.attrs.peer_recipient_lid
208
+ }
209
+
210
+ const storeMappingFromEnvelope = async (stanza, sender, repository, decryptionJid, logger) => {
211
+ const senderAlt = extractSenderAlt(stanza)
212
+ if (senderAlt && WABinary_1.isLidUser(senderAlt) && WABinary_1.isJidUser(sender) && decryptionJid === sender) {
213
+ try {
214
+ await repository.lidMapping.storeLIDPNMappings([{ lid: senderAlt, pn: sender }])
215
+ if (typeof repository.migrateSession === 'function') {
216
+ await repository.migrateSession(sender, senderAlt)
217
+ }
218
+ logger.debug({ sender, senderAlt }, 'Stored LID mapping from envelope')
219
+ } catch (error) {
220
+ logger.warn({ sender, senderAlt, error }, 'Failed to store LID mapping')
221
+ }
222
+ }
201
223
  }
202
- export const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
203
- const { fullMessage, author, sender } = decodeMessageNode(stanza, meId, meLid);
224
+
225
+ const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
226
+ const { fullMessage, author, sender } = decodeMessageNode(stanza, meId, meLid)
204
227
  return {
205
228
  fullMessage,
206
229
  category: stanza.attrs.category,
207
230
  author,
208
231
  async decrypt() {
209
- let decryptables = 0;
232
+ let decryptables = 0
210
233
  if (Array.isArray(stanza.content)) {
211
- for (const { tag, attrs, content } of stanza.content) {
234
+ // FIX: proses node non-skmsg (msg/pkmsg/plaintext) LEBIH DULU sebelum node
235
+ // skmsg. Root cause "bot diam/nunggu" pas ada member baru join grup lalu
236
+ // langsung kirim pesan: satu stanza berisi 2 node <enc> - satu tipe
237
+ // pkmsg/msg (isinya SenderKeyDistributionMessage buat kamu) dan satu lagi
238
+ // tipe skmsg (isi pesan asli, dienkripsi pakai sender-key grup). Urutan
239
+ // array stanza.content dari server TIDAK dijamin naruh pkmsg/msg duluan.
240
+ // Kalau skmsg kebetulan diproses duluan, sender-key belum ada di store ->
241
+ // decryptGroupMessage() gagal "No SenderKeyRecord found" -> pesan pertama
242
+ // dari member baru selalu gagal decrypt & jadi stub CIPHERTEXT, padahal
243
+ // SKDM-nya baru "sampai" sepersekian detik kemudian di iterasi berikutnya.
244
+ // Reorder di sini (stable, gak ubah urutan relatif node lain seperti
245
+ // verified_name/unavailable) supaya skmsg selalu diproses PALING TERAKHIR,
246
+ // setelah semua kemungkinan SKDM sudah didaftarkan ke sender-key store.
247
+ const orderedContent = [
248
+ ...stanza.content.filter(({ tag, attrs }) => !(tag === 'enc' && attrs.type === 'skmsg')),
249
+ ...stanza.content.filter(({ tag, attrs }) => tag === 'enc' && attrs.type === 'skmsg')
250
+ ]
251
+ for (const { tag, attrs, content } of orderedContent) {
212
252
  if (tag === 'verified_name' && content instanceof Uint8Array) {
213
- const cert = proto.VerifiedNameCertificate.decode(content);
214
- const details = proto.VerifiedNameCertificate.Details.decode(cert.details);
215
- fullMessage.verifiedBizName = details.verifiedName;
253
+ const cert = WAProto_1.proto.VerifiedNameCertificate.decode(content)
254
+ const details = WAProto_1.proto.VerifiedNameCertificate.Details.decode(cert.details)
255
+ fullMessage.verifiedBizName = details.verifiedName
216
256
  }
217
257
  if (tag === 'unavailable' && attrs.type === 'view_once') {
218
- fullMessage.key.isViewOnce = true; // TODO: remove from here and add a STUB TYPE
258
+ fullMessage.key.isViewOnce = true;
219
259
  }
220
260
  if (attrs.count && tag === 'enc') {
221
- fullMessage.retryCount = Number(attrs.count);
261
+ fullMessage.retryCount = Number(attrs.count)
222
262
  }
223
263
  if (tag !== 'enc' && tag !== 'plaintext') {
224
- continue;
264
+ continue
225
265
  }
226
266
  if (!(content instanceof Uint8Array)) {
227
- continue;
228
- }
229
- decryptables += 1;
230
- let msgBuffer;
231
- const decryptionJid = await getDecryptionJid(author, repository);
232
- if (tag !== 'plaintext') {
233
- // TODO: Handle hosted devices
234
- await storeMappingFromEnvelope(stanza, author, repository, decryptionJid, logger);
267
+ continue
235
268
  }
269
+ decryptables += 1
270
+ let msgBuffer
236
271
  try {
237
- const e2eType = tag === 'plaintext' ? 'plaintext' : attrs.type;
272
+ const e2eType = tag === 'plaintext' ? 'plaintext' : attrs.type
238
273
  switch (e2eType) {
239
274
  case 'skmsg':
240
275
  msgBuffer = await repository.decryptGroupMessage({
241
276
  group: sender,
242
277
  authorJid: author,
243
278
  msg: content
244
- });
245
- break;
279
+ })
280
+ break
246
281
  case 'pkmsg':
247
- case 'msg':
282
+ case 'msg': {
283
+ const decryptionJid = await getDecryptionJid(author, repository)
284
+ await storeMappingFromEnvelope(stanza, author, repository, decryptionJid, logger)
248
285
  msgBuffer = await repository.decryptMessage({
249
286
  jid: decryptionJid,
250
287
  type: e2eType,
251
288
  ciphertext: content
252
- });
253
- break;
289
+ })
290
+ break
291
+ }
254
292
  case 'plaintext':
255
- msgBuffer = content;
256
- break;
293
+ msgBuffer = content
294
+ break
257
295
  default:
258
- throw new Error(`Unknown e2e type: ${e2eType}`);
296
+ throw new Error(`Unknown e2e type: ${e2eType}`)
259
297
  }
260
- let msg = proto.Message.decode(e2eType !== 'plaintext' ? unpadRandomMax16(msgBuffer) : msgBuffer);
261
- msg = msg.deviceSentMessage?.message || msg;
298
+ let msg = WAProto_1.proto.Message.decode(e2eType !== 'plaintext' ? generics_1.unpadRandomMax16(msgBuffer) : msgBuffer)
299
+ msg = msg.deviceSentMessage?.message || msg
262
300
  if (msg.senderKeyDistributionMessage) {
263
- //eslint-disable-next-line max-depth
264
301
  try {
265
302
  await repository.processSenderKeyDistributionMessage({
266
303
  authorJid: author,
267
304
  item: msg.senderKeyDistributionMessage
268
- });
269
- }
270
- catch (err) {
271
- logger.error({ key: fullMessage.key, err }, 'failed to process sender key distribution message');
305
+ })
306
+ } catch (err) {
307
+ logger.error({ key: fullMessage.key, err }, 'failed to decrypt message')
272
308
  }
273
309
  }
274
310
  if (fullMessage.message) {
275
- Object.assign(fullMessage.message, msg);
311
+ Object.assign(fullMessage.message, msg)
312
+ } else {
313
+ fullMessage.message = msg
276
314
  }
277
- else {
278
- fullMessage.message = msg;
315
+ if (WABinary_1.isJidGroup(sender)) {
316
+ const mtype = getTypeMessage(fullMessage.message)
317
+ const message = fullMessage.message?.[mtype]
318
+ const contextInfo = message?.contextInfo
319
+ const mentionedJid = contextInfo?.mentionedJid
320
+ const processMessageLIDs = async (msgObj, msgType) => {
321
+ if (!msgObj?.contextInfo) return false
322
+ const contextInfo = msgObj.contextInfo
323
+ const mentionedJid = contextInfo.mentionedJid
324
+ let needsUpdate = false
325
+ if (Array.isArray(mentionedJid) && mentionedJid.length > 0) {
326
+ const metadata = await global.groupMetadataCache(sender)
327
+ const updatedMentionedJid = []
328
+ for (const mentionedLid of mentionedJid) {
329
+ if (typeof mentionedLid === "string" && mentionedLid.endsWith('@lid')) {
330
+ const found = metadata.participants.find(p => p.lid === mentionedLid)
331
+ if (found) {
332
+ updatedMentionedJid.push(found.id)
333
+ if (msgObj.text) {
334
+ msgObj.text = msgObj.text.replace(new RegExp(`@${mentionedLid.split("@")[0]}`, "g"), `@${found.id.split("@")[0]}`);
335
+ } else if (msgObj.caption) {
336
+ msgObj.caption = msgObj.caption.replace(new RegExp(`@${mentionedLid.split("@")[0]}`, "g"), `@${found.id.split("@")[0]}`);
337
+ }
338
+ } else {
339
+ const lid = WABinary_1.jidNormalizedUser(mentionedLid)
340
+ const mentioned_jid = await repository.lidMapping.getPNForLID(mentionedLid)
341
+ if (mentioned_jid) {
342
+ const pn = WABinary_1.jidNormalizedUser(mentioned_jid)
343
+ await repository.lidMapping.storeLIDPNMappings([{ lid, pn }])
344
+ updatedMentionedJid.push(pn)
345
+ if (msgObj.text) {
346
+ msgObj.text = msgObj.text.replace(new RegExp(`@${mentionedLid.split("@")[0]}`, "g"), `@${pn.split("@")[0]}`);
347
+ } else if (msgObj.caption) {
348
+ msgObj.caption = msgObj.caption.replace(new RegExp(`@${mentionedLid.split("@")[0]}`, "g"), `@${pn.split("@")[0]}`);
349
+ }
350
+ } else {
351
+ updatedMentionedJid.push(mentionedLid)
352
+ }
353
+ }
354
+ needsUpdate = true
355
+ } else {
356
+ updatedMentionedJid.push(mentionedLid)
357
+ }
358
+ }
359
+ if (needsUpdate) {
360
+ msgObj.contextInfo.mentionedJid = updatedMentionedJid
361
+ }
362
+ }
363
+ return needsUpdate
364
+ }
365
+ const quotedMessage = contextInfo?.quotedMessage
366
+ if (quotedMessage) {
367
+ const quotedMtype = getTypeMessage(quotedMessage)
368
+ const quotedMsgObj = quotedMessage[quotedMtype]
369
+ if (quotedMsgObj?.contextInfo) {
370
+ await processMessageLIDs(quotedMsgObj, quotedMtype)
371
+ }
372
+ }
279
373
  }
280
- }
281
- catch (err) {
374
+ } catch (err) {
282
375
  const errorContext = {
283
376
  key: fullMessage.key,
284
377
  err,
@@ -286,26 +379,32 @@ export const decryptMessageNode = (stanza, meId, meLid, repository, logger) => {
286
379
  sender,
287
380
  author,
288
381
  isSessionRecordError: isSessionRecordError(err)
289
- };
290
- logger.error(errorContext, 'failed to decrypt message');
291
- fullMessage.messageStubType = proto.WebMessageInfo.StubType.CIPHERTEXT;
292
- fullMessage.messageStubParameters = [err.message.toString()];
382
+ }
383
+ logger.error(errorContext, 'failed to decrypt message')
384
+ fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT
385
+ fullMessage.messageStubParameters = [err.message.toString()]
293
386
  }
294
387
  }
295
388
  }
296
- // if nothing was found to decrypt
389
+
297
390
  if (!decryptables && !fullMessage.key?.isViewOnce) {
298
- fullMessage.messageStubType = proto.WebMessageInfo.StubType.CIPHERTEXT;
299
- fullMessage.messageStubParameters = [NO_MESSAGE_FOUND_ERROR_TEXT];
391
+ fullMessage.messageStubType = WAProto_1.proto.WebMessageInfo.StubType.CIPHERTEXT
392
+ fullMessage.messageStubParameters = [NO_MESSAGE_FOUND_ERROR_TEXT]
300
393
  }
301
394
  }
302
- };
303
- };
304
- /**
305
- * Utility function to check if an error is related to missing session record
306
- */
395
+ }
396
+ }
397
+
307
398
  function isSessionRecordError(error) {
308
- const errorMessage = error?.message || error?.toString() || '';
309
- return DECRYPTION_RETRY_CONFIG.sessionRecordErrors.some(errorPattern => errorMessage.includes(errorPattern));
399
+ const errorMessage = error?.message || error?.toString() || ''
400
+ return DECRYPTION_RETRY_CONFIG.sessionRecordErrors.some(errorPattern => errorMessage.includes(errorPattern))
310
401
  }
311
- //# sourceMappingURL=decode-wa-message.js.map
402
+
403
+ module.exports = {
404
+ NACK_REASONS,
405
+ decodeMessageNode,
406
+ decryptMessageNode,
407
+ MISSING_KEYS_ERROR_TEXT,
408
+ DECRYPTION_RETRY_CONFIG,
409
+ NO_MESSAGE_FOUND_ERROR_TEXT
410
+ }