@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.
- package/LICENSE +1 -1
- package/README.md +839 -267
- package/WAProto/GenerateStatics.sh +4 -3
- package/WAProto/WAProto.proto +511 -1215
- package/WAProto/index.d.ts +55 -14017
- package/WAProto/index.js +29 -97689
- package/lib/Defaults/index.d.ts +74 -72
- package/lib/Defaults/index.js +108 -94
- package/lib/Signal/Group/ciphertext-message.d.ts +7 -8
- package/lib/Signal/Group/ciphertext-message.js +16 -9
- package/lib/Signal/Group/group-session-builder.d.ts +13 -11
- package/lib/Signal/Group/group-session-builder.js +61 -19
- package/lib/Signal/Group/group_cipher.d.ts +16 -14
- package/lib/Signal/Group/group_cipher.js +70 -41
- package/lib/Signal/Group/index.d.ts +11 -12
- package/lib/Signal/Group/index.js +61 -12
- package/lib/Signal/Group/keyhelper.d.ts +14 -9
- package/lib/Signal/Group/keyhelper.js +58 -10
- package/lib/Signal/Group/sender-chain-key.d.ts +13 -13
- package/lib/Signal/Group/sender-chain-key.js +34 -13
- package/lib/Signal/Group/sender-key-distribution-message.d.ts +16 -16
- package/lib/Signal/Group/sender-key-distribution-message.js +36 -28
- package/lib/Signal/Group/sender-key-message.d.ts +18 -18
- package/lib/Signal/Group/sender-key-message.js +45 -38
- package/lib/Signal/Group/sender-key-name.d.ts +15 -14
- package/lib/Signal/Group/sender-key-name.js +31 -20
- package/lib/Signal/Group/sender-key-record.d.ts +25 -24
- package/lib/Signal/Group/sender-key-record.js +35 -18
- package/lib/Signal/Group/sender-key-state.d.ts +34 -29
- package/lib/Signal/Group/sender-key-state.js +100 -37
- package/lib/Signal/Group/sender-message-key.d.ts +10 -11
- package/lib/Signal/Group/sender-message-key.js +22 -15
- package/lib/Signal/libsignal.d.ts +8 -5
- package/lib/Signal/libsignal.js +142 -288
- package/lib/Signal/lid-mapping.d.ts +28 -23
- package/lib/Signal/lid-mapping.js +184 -277
- package/lib/Socket/Client/index.d.ts +2 -3
- package/lib/Socket/Client/index.js +22 -3
- package/lib/Socket/Client/types.d.ts +15 -15
- package/lib/Socket/Client/types.js +15 -8
- package/lib/Socket/Client/websocket.d.ts +12 -12
- package/lib/Socket/Client/websocket.js +37 -29
- package/lib/Socket/business.d.ts +178 -208
- package/lib/Socket/business.js +127 -91
- package/lib/Socket/chats.d.ts +93 -120
- package/lib/Socket/chats.js +652 -727
- package/lib/Socket/community.js +10 -2
- package/lib/Socket/groups.d.ts +111 -143
- package/lib/Socket/groups.js +186 -165
- package/lib/Socket/index.d.ts +183 -252
- package/lib/Socket/index.js +18 -38
- package/lib/Socket/messages-recv.d.ts +167 -196
- package/lib/Socket/messages-recv.js +1567 -1443
- package/lib/Socket/messages-send.d.ts +158 -192
- package/lib/Socket/messages-send.js +1208 -1102
- package/lib/Socket/newsletter.d.ts +138 -163
- package/lib/Socket/newsletter.js +249 -153
- package/lib/Socket/socket.d.ts +36 -50
- package/lib/Socket/socket.js +820 -749
- package/lib/Store/index.d.ts +4 -4
- package/lib/Store/index.js +24 -4
- package/lib/Store/make-in-memory-store.d.ts +104 -44
- package/lib/Store/make-in-memory-store.js +213 -199
- package/lib/Store/make-ordered-dictionary.d.ts +12 -13
- package/lib/Store/make-ordered-dictionary.js +45 -38
- package/lib/Store/object-repository.d.ts +10 -11
- package/lib/Store/object-repository.js +16 -9
- package/lib/Types/Auth.d.ts +97 -93
- package/lib/Types/Auth.js +3 -2
- package/lib/Types/Bussines.js +3 -2
- package/lib/Types/Call.d.ts +13 -14
- package/lib/Types/Call.js +3 -2
- package/lib/Types/Chat.d.ts +97 -78
- package/lib/Types/Chat.js +9 -8
- package/lib/Types/Contact.d.ts +9 -12
- package/lib/Types/Contact.js +3 -2
- package/lib/Types/Events.d.ts +176 -206
- package/lib/Types/Events.js +3 -2
- package/lib/Types/GroupMetadata.d.ts +48 -53
- package/lib/Types/GroupMetadata.js +3 -2
- package/lib/Types/Label.d.ts +14 -13
- package/lib/Types/Label.js +30 -24
- package/lib/Types/LabelAssociation.d.ts +20 -15
- package/lib/Types/LabelAssociation.js +12 -6
- package/lib/Types/Message.d.ts +412 -248
- package/lib/Types/Message.js +19 -17
- package/lib/Types/Product.d.ts +71 -58
- package/lib/Types/Product.js +3 -2
- package/lib/Types/Signal.d.ts +82 -71
- package/lib/Types/Signal.js +3 -2
- package/lib/Types/Socket.d.ts +81 -76
- package/lib/Types/Socket.js +3 -3
- package/lib/Types/State.d.ts +19 -75
- package/lib/Types/State.js +14 -56
- package/lib/Types/USync.d.ts +8 -8
- package/lib/Types/USync.js +3 -2
- package/lib/Types/index.d.ts +62 -47
- package/lib/Types/index.js +50 -26
- package/lib/Utils/auth-utils.d.ts +10 -13
- package/lib/Utils/auth-utils.js +472 -213
- package/lib/Utils/business.d.ts +20 -14
- package/lib/Utils/business.js +134 -110
- package/lib/Utils/chat-utils.d.ts +70 -88
- package/lib/Utils/chat-utils.js +403 -466
- package/lib/Utils/crypto.d.ts +46 -27
- package/lib/Utils/crypto.js +188 -117
- package/lib/Utils/decode-wa-message.d.ts +45 -58
- package/lib/Utils/decode-wa-message.js +311 -212
- package/lib/Utils/event-buffer.d.ts +17 -14
- package/lib/Utils/event-buffer.js +296 -321
- package/lib/Utils/generics.d.ts +92 -66
- package/lib/Utils/generics.js +436 -270
- package/lib/Utils/history.d.ts +23 -24
- package/lib/Utils/history.js +76 -106
- package/lib/Utils/index.d.ts +21 -24
- package/lib/Utils/index.js +41 -24
- package/lib/Utils/link-preview.d.ts +14 -12
- package/lib/Utils/link-preview.js +75 -40
- package/lib/Utils/logger.d.ts +11 -10
- package/lib/Utils/logger.js +7 -3
- package/lib/Utils/lt-hash.d.ts +14 -8
- package/lib/Utils/lt-hash.js +53 -3
- package/lib/Utils/make-mutex.d.ts +7 -7
- package/lib/Utils/make-mutex.js +44 -28
- package/lib/Utils/message-retry-manager.d.ts +88 -115
- package/lib/Utils/message-retry-manager.js +160 -265
- package/lib/Utils/messages-media.d.ts +107 -105
- package/lib/Utils/messages-media.js +619 -548
- package/lib/Utils/messages.d.ts +66 -52
- package/lib/Utils/messages.js +1558 -1730
- package/lib/Utils/noise-handler.d.ts +18 -18
- package/lib/Utils/noise-handler.js +130 -176
- package/lib/Utils/process-message.d.ts +32 -43
- package/lib/Utils/process-message.js +282 -484
- package/lib/Utils/rich-message-utils.js +724 -1220
- package/lib/Utils/signal.d.ts +32 -37
- package/lib/Utils/signal.js +105 -140
- package/lib/Utils/use-multi-file-auth-state.d.ts +5 -5
- package/lib/Utils/use-multi-file-auth-state.js +120 -70
- package/lib/Utils/use-single-file-auth-state.d.ts +13 -11
- package/lib/Utils/use-single-file-auth-state.js +66 -92
- package/lib/Utils/validate-connection.d.ts +13 -11
- package/lib/Utils/validate-connection.js +113 -128
- package/lib/WABinary/constants.d.ts +27 -25
- package/lib/WABinary/constants.js +1292 -1451
- package/lib/WABinary/decode.d.ts +9 -7
- package/lib/WABinary/decode.js +189 -163
- package/lib/WABinary/encode.d.ts +3 -3
- package/lib/WABinary/encode.js +155 -110
- package/lib/WABinary/generic-utils.d.ts +27 -14
- package/lib/WABinary/generic-utils.js +105 -177
- package/lib/WABinary/index.d.ts +5 -6
- package/lib/WABinary/index.js +25 -6
- package/lib/WABinary/jid-utils.d.ts +54 -41
- package/lib/WABinary/jid-utils.js +152 -83
- package/lib/WABinary/types.d.ts +13 -10
- package/lib/WABinary/types.js +3 -2
- package/lib/WAM/BinaryInfo.d.ts +15 -8
- package/lib/WAM/BinaryInfo.js +14 -7
- package/lib/WAM/constants.d.ts +37 -30
- package/lib/WAM/constants.js +11983 -19465
- package/lib/WAM/encode.d.ts +3 -3
- package/lib/WAM/encode.js +109 -95
- package/lib/WAM/index.d.ts +3 -4
- package/lib/WAM/index.js +23 -4
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +9 -9
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +21 -37
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +22 -19
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +26 -18
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +12 -11
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +20 -12
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +12 -11
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +24 -16
- package/lib/WAUSync/Protocols/index.d.ts +6 -6
- package/lib/WAUSync/Protocols/index.js +26 -6
- package/lib/WAUSync/USyncQuery.d.ts +28 -27
- package/lib/WAUSync/USyncQuery.js +62 -68
- package/lib/WAUSync/USyncUser.d.ts +10 -15
- package/lib/WAUSync/USyncUser.js +19 -20
- package/lib/WAUSync/index.d.ts +3 -4
- package/lib/WAUSync/index.js +23 -4
- package/lib/index.d.ts +12 -11
- package/lib/index.js +39 -12
- package/package.json +43 -87
- package/engine-requirements.js +0 -10
|
@@ -1,42 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
38
|
-
|
|
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
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
124
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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
|
-
|
|
142
|
-
author = participant
|
|
143
|
-
|
|
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
|
-
|
|
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
|
-
|
|
107
|
+
msg_type = isParticipantMe ? 'peer_broadcast' : 'other_broadcast'
|
|
155
108
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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:
|
|
174
|
-
remoteJidAlt:
|
|
175
|
-
|
|
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:
|
|
182
|
-
|
|
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:
|
|
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
|
-
|
|
203
|
-
|
|
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
|
-
|
|
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;
|
|
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
|
-
|
|
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
|
-
|
|
278
|
-
fullMessage.message
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
}
|