@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.
- package/README.md +96 -85
- package/lib/Defaults/connection.js +39 -0
- package/lib/Defaults/constants.js +50 -0
- package/lib/Defaults/history.js +13 -0
- package/lib/Defaults/index.js +36 -151
- package/lib/Defaults/media.js +43 -0
- package/lib/Defaults/phonenumber-mcc.json +221 -221
- package/lib/Defaults/prefix.js +12 -0
- package/lib/Defaults/vialeys-version.json +7 -0
- package/lib/Signal/Group/ciphertext-message.js +10 -15
- package/lib/Signal/Group/group-session-builder.js +34 -60
- package/lib/Signal/Group/group_cipher.js +69 -76
- package/lib/Signal/Group/index.js +41 -60
- package/lib/Signal/Group/keyhelper.js +12 -57
- package/lib/Signal/Group/sender-chain-key.js +20 -33
- package/lib/Signal/Group/sender-key-distribution-message.js +43 -48
- package/lib/Signal/Group/sender-key-message.js +58 -53
- package/lib/Signal/Group/sender-key-name.js +21 -31
- package/lib/Signal/Group/sender-key-record.js +21 -34
- package/lib/Signal/Group/sender-key-state.js +59 -106
- package/lib/Signal/Group/sender-message-key.js +16 -21
- package/lib/Signal/libsignal.js +282 -203
- package/lib/Signal/lid-mapping.js +164 -184
- package/lib/Socket/Client/index.js +31 -22
- package/lib/Socket/Client/types.js +9 -15
- package/lib/Socket/Client/websocket.js +42 -37
- package/lib/Socket/business.js +212 -336
- package/lib/Socket/chats.js +696 -940
- package/lib/Socket/community.js +454 -369
- package/lib/Socket/groups.js +278 -280
- package/lib/Socket/index.js +9 -21
- package/lib/Socket/messages-recv.js +1027 -1570
- package/lib/Socket/messages-send.js +1180 -1136
- package/lib/Socket/mex.js +59 -0
- package/lib/Socket/newsletter.js +193 -251
- package/lib/Socket/socket.js +758 -898
- package/lib/Store/index.js +35 -24
- package/lib/Store/make-cache-manager-store.js +53 -66
- package/lib/Store/make-in-memory-store.js +319 -325
- package/lib/Store/make-ordered-dictionary.js +49 -57
- package/lib/Store/object-repository.js +10 -15
- package/lib/Types/Auth.js +2 -3
- package/lib/Types/Bussines.js +2 -3
- package/lib/Types/Call.js +2 -3
- package/lib/Types/Chat.js +10 -9
- package/lib/Types/Contact.js +2 -3
- package/lib/Types/Events.js +2 -3
- package/lib/Types/GroupMetadata.js +2 -3
- package/lib/Types/Label.js +6 -12
- package/lib/Types/LabelAssociation.js +4 -13
- package/lib/Types/Message.js +10 -18
- package/lib/Types/MexUpdates.js +15 -18
- package/lib/Types/Newsletter.js +26 -34
- package/lib/Types/Product.js +2 -3
- package/lib/Types/Signal.js +2 -3
- package/lib/Types/Socket.js +2 -3
- package/lib/Types/State.js +8 -13
- package/lib/Types/USync.js +2 -3
- package/lib/Types/index.js +49 -40
- package/lib/Utils/auth-utils.js +190 -495
- package/lib/Utils/browser-utils.js +29 -0
- package/lib/Utils/business.js +177 -199
- package/lib/Utils/chat-utils.js +711 -624
- package/lib/Utils/crypto.js +116 -161
- package/lib/Utils/decode-wa-message.js +225 -321
- package/lib/Utils/event-buffer.js +363 -405
- package/lib/Utils/generics.js +318 -472
- package/lib/Utils/history.js +72 -76
- package/lib/Utils/index.js +49 -41
- package/lib/Utils/link-preview.js +59 -103
- package/lib/Utils/logger.js +4 -7
- package/lib/Utils/lt-hash.js +29 -42
- package/lib/Utils/make-mutex.js +26 -42
- package/lib/Utils/message-retry-manager.js +134 -160
- package/lib/Utils/messages-media.js +665 -731
- package/lib/Utils/messages.js +518 -1
- package/lib/Utils/noise-handler.js +127 -125
- package/lib/Utils/pre-key-manager.js +86 -0
- package/lib/Utils/process-message.js +739 -351
- package/lib/Utils/signal.js +146 -129
- package/lib/Utils/use-multi-file-auth-state.js +68 -135
- package/lib/Utils/validate-connection.js +183 -142
- package/lib/Utils/vialeys-event-stream.js +41 -0
- package/lib/WABinary/constants.js +1281 -1289
- package/lib/WABinary/decode.js +145 -200
- package/lib/WABinary/encode.js +149 -202
- package/lib/WABinary/generic-utils.js +79 -97
- package/lib/WABinary/index.js +36 -25
- package/lib/WABinary/jid-utils.js +91 -123
- package/lib/WABinary/types.js +2 -3
- package/lib/WAM/BinaryInfo.js +8 -13
- package/lib/WAM/constants.js +16584 -11464
- package/lib/WAM/encode.js +117 -133
- package/lib/WAM/index.js +34 -23
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +62 -69
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +11 -25
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +32 -44
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +13 -23
- package/lib/WAUSync/Protocols/USyncLIDProtocol.js +24 -38
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +17 -31
- package/lib/WAUSync/Protocols/index.js +37 -26
- package/lib/WAUSync/USyncQuery.js +66 -66
- package/lib/WAUSync/USyncUser.js +13 -18
- package/lib/WAUSync/index.js +34 -23
- package/lib/index.js +95 -28
- package/package.json +4 -3
- package/lib/Defaults/baileys-version.json +0 -3
- package/lib/Signal/Group/queue-job.d.ts +0 -1
- package/lib/Signal/Group/queue-job.js +0 -57
- package/lib/Socket/usync.d.ts +0 -37
- package/lib/Socket/usync.js +0 -83
- package/lib/Utils/baileys-event-stream.d.ts +0 -18
- package/lib/Utils/baileys-event-stream.js +0 -70
- package/lib/Utils/signal-housekeeping.d.ts +0 -19
- package/lib/Utils/signal-housekeeping.js +0 -73
- package/lib/Utils/use-mongo-file-auth-state.d.ts +0 -6
- package/lib/Utils/use-mongo-file-auth-state.js +0 -84
- package/lib/Utils/use-single-file-auth-state.d.ts +0 -13
- package/lib/Utils/use-single-file-auth-state.js +0 -80
|
@@ -1,1339 +1,1378 @@
|
|
|
1
|
-
"use strict"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const { default: NodeCache } = require("@cacheable/node-cache");
|
|
4
|
+
const { Boom: Boom } = require("@hapi/boom");
|
|
5
|
+
const { randomBytes: randomBytes } = require("crypto");
|
|
6
|
+
const { proto: proto } = require("../../WAProto");
|
|
7
|
+
const {
|
|
8
|
+
DEFAULT_CACHE_TTLS: DEFAULT_CACHE_TTLS,
|
|
9
|
+
WA_DEFAULT_EPHEMERAL: WA_DEFAULT_EPHEMERAL,
|
|
10
|
+
} = require("../Defaults/constants");
|
|
11
|
+
const {
|
|
12
|
+
delay: delay,
|
|
13
|
+
assertMediaContent: assertMediaContent,
|
|
14
|
+
bindWaitForEvent: bindWaitForEvent,
|
|
15
|
+
decryptMediaRetryData: decryptMediaRetryData,
|
|
16
|
+
encodeNewsletterMessage: encodeNewsletterMessage,
|
|
17
|
+
encodeSignedDeviceIdentity: encodeSignedDeviceIdentity,
|
|
18
|
+
encodeWAMessage: encodeWAMessage,
|
|
19
|
+
encryptMediaRetryRequest: encryptMediaRetryRequest,
|
|
20
|
+
extractDeviceJids: extractDeviceJids,
|
|
21
|
+
generateMessageID: generateMessageID,
|
|
22
|
+
generateParticipantHashV2: generateParticipantHashV2,
|
|
23
|
+
generateWAMessage: generateWAMessage,
|
|
24
|
+
generateWAMessageFromContent: generateWAMessageFromContent,
|
|
25
|
+
getStatusCodeForMediaRetry: getStatusCodeForMediaRetry,
|
|
26
|
+
getUrlFromDirectPath: getUrlFromDirectPath,
|
|
27
|
+
getWAUploadToServer: getWAUploadToServer,
|
|
28
|
+
MessageRetryManager: MessageRetryManager,
|
|
29
|
+
normalizeMessageContent: normalizeMessageContent,
|
|
30
|
+
parseAndInjectE2ESessions: parseAndInjectE2ESessions,
|
|
31
|
+
unixTimestampSeconds: unixTimestampSeconds,
|
|
32
|
+
prepareAlbumMessageContent: prepareAlbumMessageContent,
|
|
33
|
+
aggregateMessageKeysNotFromMe: aggregateMessageKeysNotFromMe,
|
|
34
|
+
} = require("../Utils");
|
|
35
|
+
const { WAMessageAddressingMode: WAMessageAddressingMode } = require("../Types");
|
|
36
|
+
const {
|
|
37
|
+
areJidsSameUser: areJidsSameUser,
|
|
38
|
+
getBinaryNodeChild: getBinaryNodeChild,
|
|
39
|
+
getBinaryNodeChildren: getBinaryNodeChildren,
|
|
40
|
+
getBinaryFilteredBizBot: getBinaryFilteredBizBot,
|
|
41
|
+
getBinaryFilteredButtons: getBinaryFilteredButtons,
|
|
42
|
+
isHostedLidUser: isHostedLidUser,
|
|
43
|
+
isHostedPnUser: isHostedPnUser,
|
|
44
|
+
isJidNewsletter: isJidNewsletter,
|
|
45
|
+
isJidGroup: isJidGroup,
|
|
46
|
+
isLidUser: isLidUser,
|
|
47
|
+
isPnUser: isPnUser,
|
|
48
|
+
jidDecode: jidDecode,
|
|
49
|
+
jidEncode: jidEncode,
|
|
50
|
+
jidNormalizedUser: jidNormalizedUser,
|
|
51
|
+
STORIES_JID: STORIES_JID,
|
|
52
|
+
S_WHATSAPP_NET: S_WHATSAPP_NET,
|
|
53
|
+
} = require("../WABinary");
|
|
54
|
+
const { USyncUser: USyncUser, USyncQuery: USyncQuery } = require("../WAUSync");
|
|
55
|
+
const { makeNewsletterSocket: makeNewsletterSocket } = require("./newsletter");
|
|
56
|
+
const { getUrlInfo: getUrlInfo } = require("../Utils/link-preview");
|
|
57
|
+
const { makeKeyedMutex: makeKeyedMutex } = require("../Utils/make-mutex");
|
|
26
58
|
const makeMessagesSocket = (config) => {
|
|
27
59
|
const {
|
|
28
|
-
logger,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
} = config
|
|
37
|
-
const
|
|
60
|
+
logger: logger,
|
|
61
|
+
linkPreviewImageThumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
62
|
+
generateHighQualityLinkPreview: generateHighQualityLinkPreview,
|
|
63
|
+
options: httpRequestOptions,
|
|
64
|
+
patchMessageBeforeSending: patchMessageBeforeSending,
|
|
65
|
+
cachedGroupMetadata: cachedGroupMetadata,
|
|
66
|
+
enableRecentMessageCache: enableRecentMessageCache,
|
|
67
|
+
maxMsgRetryCount: maxMsgRetryCount,
|
|
68
|
+
} = config;
|
|
69
|
+
const conn = makeNewsletterSocket(config);
|
|
38
70
|
const {
|
|
39
|
-
ev,
|
|
40
|
-
authState,
|
|
41
|
-
|
|
42
|
-
signalRepository,
|
|
43
|
-
upsertMessage,
|
|
44
|
-
createCallLink,
|
|
45
|
-
query,
|
|
46
|
-
fetchPrivacySettings,
|
|
47
|
-
sendNode,
|
|
48
|
-
groupQuery,
|
|
49
|
-
groupMetadata,
|
|
50
|
-
groupToggleEphemeral,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
} =
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
71
|
+
ev: ev,
|
|
72
|
+
authState: authState,
|
|
73
|
+
messageMutex: messageMutex,
|
|
74
|
+
signalRepository: signalRepository,
|
|
75
|
+
upsertMessage: upsertMessage,
|
|
76
|
+
createCallLink: createCallLink,
|
|
77
|
+
query: query,
|
|
78
|
+
fetchPrivacySettings: fetchPrivacySettings,
|
|
79
|
+
sendNode: sendNode,
|
|
80
|
+
groupQuery: groupQuery,
|
|
81
|
+
groupMetadata: groupMetadata,
|
|
82
|
+
groupToggleEphemeral: groupToggleEphemeral,
|
|
83
|
+
executeUSyncQuery: executeUSyncQuery,
|
|
84
|
+
newsletterMetadata: newsletterMetadata,
|
|
85
|
+
} = conn;
|
|
86
|
+
const userDevicesCache =
|
|
87
|
+
config.userDevicesCache ||
|
|
88
|
+
new NodeCache({
|
|
89
|
+
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
|
|
90
|
+
useClones: false,
|
|
91
|
+
});
|
|
92
|
+
const peerSessionsCache = new NodeCache({
|
|
93
|
+
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
|
|
94
|
+
useClones: false,
|
|
95
|
+
});
|
|
96
|
+
const messageRetryManager = enableRecentMessageCache
|
|
97
|
+
? new MessageRetryManager(logger, maxMsgRetryCount)
|
|
98
|
+
: null;
|
|
99
|
+
const encryptionMutex = makeKeyedMutex();
|
|
100
|
+
let mediaConn;
|
|
65
101
|
const refreshMediaConn = async (forceGet = false) => {
|
|
66
|
-
const media = await mediaConn
|
|
67
|
-
if (
|
|
102
|
+
const media = await mediaConn;
|
|
103
|
+
if (
|
|
104
|
+
!media ||
|
|
105
|
+
forceGet ||
|
|
106
|
+
new Date().getTime() - media.fetchDate.getTime() > media.ttl * 1e3
|
|
107
|
+
) {
|
|
68
108
|
mediaConn = (async () => {
|
|
69
109
|
const result = await query({
|
|
70
|
-
tag:
|
|
71
|
-
attrs: {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
},
|
|
76
|
-
content: [{
|
|
77
|
-
tag: 'media_conn',
|
|
78
|
-
attrs: {}
|
|
79
|
-
}]
|
|
80
|
-
})
|
|
81
|
-
const mediaConnNode = WABinary_1.getBinaryNodeChild(result, 'media_conn')
|
|
110
|
+
tag: "iq",
|
|
111
|
+
attrs: { type: "set", xmlns: "w:m", to: S_WHATSAPP_NET },
|
|
112
|
+
content: [{ tag: "media_conn", attrs: {} }],
|
|
113
|
+
});
|
|
114
|
+
const mediaConnNode = getBinaryNodeChild(result, "media_conn");
|
|
82
115
|
const node = {
|
|
83
|
-
hosts:
|
|
84
|
-
attrs
|
|
85
|
-
}) => ({
|
|
116
|
+
hosts: getBinaryNodeChildren(mediaConnNode, "host").map(({ attrs: attrs }) => ({
|
|
86
117
|
hostname: attrs.hostname,
|
|
87
118
|
maxContentLengthBytes: +attrs.maxContentLengthBytes,
|
|
88
119
|
})),
|
|
89
120
|
auth: mediaConnNode.attrs.auth,
|
|
90
121
|
ttl: +mediaConnNode.attrs.ttl,
|
|
91
|
-
fetchDate: new Date()
|
|
92
|
-
}
|
|
93
|
-
logger.debug(
|
|
94
|
-
return node
|
|
95
|
-
})()
|
|
122
|
+
fetchDate: new Date(),
|
|
123
|
+
};
|
|
124
|
+
logger.debug("fetched media conn");
|
|
125
|
+
return node;
|
|
126
|
+
})();
|
|
96
127
|
}
|
|
97
|
-
return mediaConn
|
|
98
|
-
}
|
|
99
|
-
|
|
128
|
+
return mediaConn;
|
|
129
|
+
};
|
|
100
130
|
const sendReceipt = async (jid, participant, messageIds, type) => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
attrs: {
|
|
104
|
-
id: messageIds[0],
|
|
105
|
-
},
|
|
131
|
+
if (!messageIds || messageIds.length === 0) {
|
|
132
|
+
throw new Boom("missing ids in receipt");
|
|
106
133
|
}
|
|
107
|
-
const
|
|
134
|
+
const node = { tag: "receipt", attrs: { id: messageIds[0] } };
|
|
135
|
+
const isReadReceipt = type === "read" || type === "read-self";
|
|
108
136
|
if (isReadReceipt) {
|
|
109
|
-
node.attrs.t =
|
|
137
|
+
node.attrs.t = unixTimestampSeconds().toString();
|
|
110
138
|
}
|
|
111
|
-
if (type ===
|
|
112
|
-
node.attrs.recipient = jid
|
|
113
|
-
node.attrs.to = participant
|
|
139
|
+
if (type === "sender" && (isPnUser(jid) || isLidUser(jid))) {
|
|
140
|
+
node.attrs.recipient = jid;
|
|
141
|
+
node.attrs.to = participant;
|
|
114
142
|
} else {
|
|
115
|
-
node.attrs.to = jid
|
|
143
|
+
node.attrs.to = jid;
|
|
116
144
|
if (participant) {
|
|
117
|
-
node.attrs.participant = participant
|
|
145
|
+
node.attrs.participant = participant;
|
|
118
146
|
}
|
|
119
147
|
}
|
|
120
148
|
if (type) {
|
|
121
|
-
node.attrs.type =
|
|
149
|
+
node.attrs.type = type;
|
|
122
150
|
}
|
|
123
|
-
const remainingMessageIds = messageIds.slice(1)
|
|
151
|
+
const remainingMessageIds = messageIds.slice(1);
|
|
124
152
|
if (remainingMessageIds.length) {
|
|
125
|
-
node.content = [
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
id
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
153
|
+
node.content = [
|
|
154
|
+
{
|
|
155
|
+
tag: "list",
|
|
156
|
+
attrs: {},
|
|
157
|
+
content: remainingMessageIds.map((id) => ({
|
|
158
|
+
tag: "item",
|
|
159
|
+
attrs: { id: id },
|
|
160
|
+
})),
|
|
161
|
+
},
|
|
162
|
+
];
|
|
135
163
|
}
|
|
136
|
-
logger.debug({
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}, 'sending receipt for messages')
|
|
140
|
-
await sendNode(node)
|
|
141
|
-
}
|
|
142
|
-
|
|
164
|
+
logger.debug({ attrs: node.attrs, messageIds: messageIds }, "sending receipt for messages");
|
|
165
|
+
await sendNode(node);
|
|
166
|
+
};
|
|
143
167
|
const sendReceipts = async (keys, type) => {
|
|
144
|
-
const recps =
|
|
145
|
-
for (const { jid, participant, messageIds } of recps) {
|
|
146
|
-
await sendReceipt(jid, participant, messageIds, type)
|
|
168
|
+
const recps = aggregateMessageKeysNotFromMe(keys);
|
|
169
|
+
for (const { jid: jid, participant: participant, messageIds: messageIds } of recps) {
|
|
170
|
+
await sendReceipt(jid, participant, messageIds, type);
|
|
147
171
|
}
|
|
148
|
-
}
|
|
149
|
-
|
|
172
|
+
};
|
|
150
173
|
const readMessages = async (keys) => {
|
|
151
|
-
const privacySettings = await fetchPrivacySettings()
|
|
152
|
-
const readType = privacySettings.readreceipts ===
|
|
153
|
-
await sendReceipts(keys, readType)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
const deduplicateLidPnJids = (jids) => {
|
|
157
|
-
const lidUsers = new Set()
|
|
158
|
-
const filteredJids = []
|
|
159
|
-
|
|
160
|
-
for (const jid of jids) {
|
|
161
|
-
if (WABinary_1.isLidUser(jid)) {
|
|
162
|
-
const user = WABinary_1.jidDecode(jid)?.user
|
|
163
|
-
if (user) lidUsers.add(user)
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
for (const jid of jids) {
|
|
168
|
-
if (WABinary_1.isJidUser(jid)) {
|
|
169
|
-
const user = WABinary_1.jidDecode(jid)?.user
|
|
170
|
-
if (user && lidUsers.has(user)) {
|
|
171
|
-
logger.debug({
|
|
172
|
-
jid
|
|
173
|
-
}, 'Skipping PN - LID version exists')
|
|
174
|
-
continue
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
filteredJids.push(jid)
|
|
178
|
-
}
|
|
179
|
-
return filteredJids
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const profilePictureUrl = async (jid) => {
|
|
183
|
-
if (WABinary_1.isJidNewsletter(jid)) {
|
|
184
|
-
let node = await newsletterWMexQuery(undefined, Types_1.QueryIds.METADATA, {
|
|
185
|
-
input: {
|
|
186
|
-
key: jid,
|
|
187
|
-
type: 'JID',
|
|
188
|
-
view_role: 'GUEST'
|
|
189
|
-
},
|
|
190
|
-
fetch_viewer_metadata: true,
|
|
191
|
-
fetch_full_image: true,
|
|
192
|
-
fetch_creation_time: true
|
|
193
|
-
})
|
|
194
|
-
let result = WABinary_1.getBinaryNodeChild(node, 'result')?.content?.toString()
|
|
195
|
-
let metadata = JSON.parse(result).data[Types_1.XWAPaths.NEWSLETTER]
|
|
196
|
-
return Utils_1.getUrlFromDirectPath(metadata.thread_metadata.picture?.direct_path || '')
|
|
197
|
-
} else {
|
|
198
|
-
const result = await query({
|
|
199
|
-
tag: 'iq',
|
|
200
|
-
attrs: {
|
|
201
|
-
target: WABinary_1.jidNormalizedUser(jid),
|
|
202
|
-
to: WABinary_1.S_WHATSAPP_NET,
|
|
203
|
-
type: 'get',
|
|
204
|
-
xmlns: 'w:profile:picture'
|
|
205
|
-
},
|
|
206
|
-
content: [{
|
|
207
|
-
tag: 'picture',
|
|
208
|
-
attrs: {
|
|
209
|
-
type: 'image',
|
|
210
|
-
query: 'url'
|
|
211
|
-
}
|
|
212
|
-
}]
|
|
213
|
-
})
|
|
214
|
-
const child = WABinary_1.getBinaryNodeChild(result, 'picture')
|
|
215
|
-
return child?.attrs?.url || null
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
174
|
+
const privacySettings = await fetchPrivacySettings();
|
|
175
|
+
const readType = privacySettings.readreceipts === "all" ? "read" : "read-self";
|
|
176
|
+
await sendReceipts(keys, readType);
|
|
177
|
+
};
|
|
219
178
|
const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
|
|
220
|
-
const deviceResults = []
|
|
221
|
-
|
|
179
|
+
const deviceResults = [];
|
|
222
180
|
if (!useCache) {
|
|
223
|
-
logger.debug(
|
|
181
|
+
logger.debug("not using cache for devices");
|
|
224
182
|
}
|
|
225
|
-
|
|
226
|
-
const toFetch = []
|
|
227
|
-
|
|
228
|
-
jids = deduplicateLidPnJids(Array.from(new Set(jids)))
|
|
183
|
+
const toFetch = [];
|
|
229
184
|
const jidsWithUser = jids
|
|
230
|
-
.map(jid => {
|
|
231
|
-
const decoded =
|
|
232
|
-
const user = decoded?.user
|
|
233
|
-
const device = decoded?.device
|
|
234
|
-
const isExplicitDevice = typeof device ===
|
|
235
|
-
|
|
185
|
+
.map((jid) => {
|
|
186
|
+
const decoded = jidDecode(jid);
|
|
187
|
+
const user = decoded?.user;
|
|
188
|
+
const device = decoded?.device;
|
|
189
|
+
const isExplicitDevice = typeof device === "number" && device >= 0;
|
|
236
190
|
if (isExplicitDevice && user) {
|
|
237
|
-
deviceResults.push({
|
|
238
|
-
|
|
239
|
-
device,
|
|
240
|
-
wireJid: jid
|
|
241
|
-
});
|
|
242
|
-
return null
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
jid = WABinary_1.jidNormalizedUser(jid)
|
|
246
|
-
return {
|
|
247
|
-
jid,
|
|
248
|
-
user
|
|
191
|
+
deviceResults.push({ user: user, device: device, jid: jid });
|
|
192
|
+
return null;
|
|
249
193
|
}
|
|
194
|
+
jid = jidNormalizedUser(jid);
|
|
195
|
+
return { jid: jid, user: user };
|
|
250
196
|
})
|
|
251
|
-
.filter(jid => jid !== null)
|
|
252
|
-
|
|
253
|
-
let mgetDevices
|
|
197
|
+
.filter((jid) => jid !== null);
|
|
198
|
+
let mgetDevices;
|
|
254
199
|
if (useCache && userDevicesCache.mget) {
|
|
255
|
-
const usersToFetch = jidsWithUser.map(j => j?.user).filter(Boolean)
|
|
256
|
-
mgetDevices = await userDevicesCache.mget(usersToFetch)
|
|
200
|
+
const usersToFetch = jidsWithUser.map((j) => j?.user).filter(Boolean);
|
|
201
|
+
mgetDevices = await userDevicesCache.mget(usersToFetch);
|
|
257
202
|
}
|
|
258
|
-
|
|
259
|
-
for (const { jid, user } of jidsWithUser) {
|
|
203
|
+
for (const { jid: jid, user: user } of jidsWithUser) {
|
|
260
204
|
if (useCache) {
|
|
261
|
-
const devices =
|
|
205
|
+
const devices =
|
|
206
|
+
mgetDevices?.[user] ||
|
|
207
|
+
(userDevicesCache.mget ? undefined : await userDevicesCache.get(user));
|
|
262
208
|
if (devices) {
|
|
263
|
-
const
|
|
264
|
-
const devicesWithWire = devices.map(d => ({
|
|
209
|
+
const devicesWithJid = devices.map((d) => ({
|
|
265
210
|
...d,
|
|
266
|
-
|
|
267
|
-
}))
|
|
268
|
-
deviceResults.push(...
|
|
269
|
-
logger.trace({
|
|
270
|
-
user
|
|
271
|
-
}, 'using cache for devices')
|
|
211
|
+
jid: jidEncode(d.user, d.server, d.device),
|
|
212
|
+
}));
|
|
213
|
+
deviceResults.push(...devicesWithJid);
|
|
214
|
+
logger.trace({ user: user }, "using cache for devices");
|
|
272
215
|
} else {
|
|
273
|
-
toFetch.push(jid)
|
|
216
|
+
toFetch.push(jid);
|
|
274
217
|
}
|
|
275
218
|
} else {
|
|
276
|
-
toFetch.push(jid)
|
|
219
|
+
toFetch.push(jid);
|
|
277
220
|
}
|
|
278
221
|
}
|
|
279
|
-
|
|
280
222
|
if (!toFetch.length) {
|
|
281
|
-
return deviceResults
|
|
223
|
+
return deviceResults;
|
|
282
224
|
}
|
|
283
|
-
|
|
284
|
-
const requestedLidUsers = new Set()
|
|
225
|
+
const requestedLidUsers = new Set();
|
|
285
226
|
for (const jid of toFetch) {
|
|
286
|
-
if (
|
|
287
|
-
const user =
|
|
288
|
-
if (user) requestedLidUsers.add(user)
|
|
227
|
+
if (isLidUser(jid) || isHostedLidUser(jid)) {
|
|
228
|
+
const user = jidDecode(jid)?.user;
|
|
229
|
+
if (user) requestedLidUsers.add(user);
|
|
289
230
|
}
|
|
290
231
|
}
|
|
291
|
-
|
|
292
|
-
|
|
232
|
+
const query = new USyncQuery()
|
|
233
|
+
.withContext("message")
|
|
234
|
+
.withDeviceProtocol()
|
|
235
|
+
.withLIDProtocol();
|
|
293
236
|
for (const jid of toFetch) {
|
|
294
|
-
query.withUser(new
|
|
237
|
+
query.withUser(new USyncUser().withId(jid));
|
|
295
238
|
}
|
|
296
|
-
|
|
297
|
-
const result = await executeUSyncQuery(query)
|
|
239
|
+
const result = await executeUSyncQuery(query);
|
|
298
240
|
if (result) {
|
|
299
|
-
|
|
300
|
-
// dari hasil USync device query ini (nuiisweety nyimpen + langsung
|
|
301
|
-
// force-refresh session buat LID yang baru ketemu). Tanpa ini,
|
|
302
|
-
// pengiriman ke kontak yang butuh LID addressing bisa tetep pakai
|
|
303
|
-
// address PN yang salah/basi -> penerima gak bisa decrypt balasan
|
|
304
|
-
// bot ("Menunggu pesan ini...").
|
|
305
|
-
const lidResults = (result.list || []).filter(item => !!item.lid)
|
|
241
|
+
const lidResults = result.list.filter((a) => !!a.lid);
|
|
306
242
|
if (lidResults.length > 0) {
|
|
243
|
+
logger.trace("Storing LID maps from device call");
|
|
244
|
+
await signalRepository.lidMapping.storeLIDPNMappings(
|
|
245
|
+
lidResults.map((a) => ({ lid: a.lid, pn: a.id }))
|
|
246
|
+
);
|
|
307
247
|
try {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
248
|
+
const lids = lidResults.map((a) => a.lid);
|
|
249
|
+
if (lids.length) {
|
|
250
|
+
await assertSessions(lids, true);
|
|
251
|
+
}
|
|
252
|
+
} catch (e) {
|
|
253
|
+
logger.warn(
|
|
254
|
+
{ e: e, count: lidResults.length },
|
|
255
|
+
"failed to assert sessions for newly mapped LIDs"
|
|
256
|
+
);
|
|
315
257
|
}
|
|
316
258
|
}
|
|
317
|
-
const extracted =
|
|
318
|
-
|
|
259
|
+
const extracted = extractDeviceJids(
|
|
260
|
+
result?.list,
|
|
261
|
+
authState.creds.me.id,
|
|
262
|
+
authState.creds.me.lid,
|
|
263
|
+
ignoreZeroDevices
|
|
264
|
+
);
|
|
265
|
+
const deviceMap = {};
|
|
319
266
|
for (const item of extracted) {
|
|
320
|
-
deviceMap[item.user] = deviceMap[item.user] || []
|
|
321
|
-
deviceMap[item.user]?.push(item)
|
|
267
|
+
deviceMap[item.user] = deviceMap[item.user] || [];
|
|
268
|
+
deviceMap[item.user]?.push(item);
|
|
322
269
|
}
|
|
323
270
|
for (const [user, userDevices] of Object.entries(deviceMap)) {
|
|
324
|
-
const isLidUser = requestedLidUsers.has(user)
|
|
271
|
+
const isLidUser = requestedLidUsers.has(user);
|
|
325
272
|
for (const item of userDevices) {
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
273
|
+
const finalJid = isLidUser
|
|
274
|
+
? jidEncode(user, item.server, item.device)
|
|
275
|
+
: jidEncode(item.user, item.server, item.device);
|
|
276
|
+
deviceResults.push({ ...item, jid: finalJid });
|
|
277
|
+
logger.debug(
|
|
278
|
+
{
|
|
279
|
+
user: item.user,
|
|
280
|
+
device: item.device,
|
|
281
|
+
finalJid: finalJid,
|
|
282
|
+
usedLid: isLidUser,
|
|
283
|
+
},
|
|
284
|
+
"Processed device with LID priority"
|
|
285
|
+
);
|
|
337
286
|
}
|
|
338
287
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
}
|
|
288
|
+
if (userDevicesCache.mset) {
|
|
289
|
+
await userDevicesCache.mset(
|
|
290
|
+
Object.entries(deviceMap).map(([key, value]) => ({
|
|
291
|
+
key: key,
|
|
292
|
+
value: value,
|
|
293
|
+
}))
|
|
294
|
+
);
|
|
295
|
+
} else {
|
|
296
|
+
for (const key in deviceMap) {
|
|
297
|
+
if (deviceMap[key]) await userDevicesCache.set(key, deviceMap[key]);
|
|
350
298
|
}
|
|
351
|
-
}
|
|
299
|
+
}
|
|
300
|
+
const userDeviceUpdates = {};
|
|
301
|
+
for (const [userId, devices] of Object.entries(deviceMap)) {
|
|
302
|
+
if (devices && devices.length > 0) {
|
|
303
|
+
userDeviceUpdates[userId] = devices.map((d) => d.device?.toString() || "0");
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
if (Object.keys(userDeviceUpdates).length > 0) {
|
|
307
|
+
try {
|
|
308
|
+
await authState.keys.set({ "device-list": userDeviceUpdates });
|
|
309
|
+
logger.debug(
|
|
310
|
+
{ userCount: Object.keys(userDeviceUpdates).length },
|
|
311
|
+
"stored user device lists for bulk migration"
|
|
312
|
+
);
|
|
313
|
+
} catch (error) {
|
|
314
|
+
logger.warn({ error: error }, "failed to store user device lists");
|
|
315
|
+
}
|
|
316
|
+
}
|
|
352
317
|
}
|
|
353
|
-
return deviceResults
|
|
354
|
-
}
|
|
355
|
-
|
|
318
|
+
return deviceResults;
|
|
319
|
+
};
|
|
320
|
+
const updateMemberLabel = (jid, memberLabel) => {
|
|
321
|
+
if (!isJidGroup(jid)) {
|
|
322
|
+
throw new Error("Jid must a group!");
|
|
323
|
+
}
|
|
324
|
+
const protocolMessage = {
|
|
325
|
+
protocolMessage: {
|
|
326
|
+
type: proto.Message.ProtocolMessage.Type.GROUP_MEMBER_LABEL_CHANGE,
|
|
327
|
+
memberLabel: {
|
|
328
|
+
label: memberLabel?.slice(0, 30),
|
|
329
|
+
labelTimestamp: unixTimestampSeconds(),
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
};
|
|
333
|
+
return relayMessage(jid, protocolMessage, {
|
|
334
|
+
additionalNodes: [
|
|
335
|
+
{
|
|
336
|
+
tag: "meta",
|
|
337
|
+
attrs: { tag_reason: "user_update", appdata: "member_tag" },
|
|
338
|
+
},
|
|
339
|
+
],
|
|
340
|
+
});
|
|
341
|
+
};
|
|
356
342
|
const assertSessions = async (jids, force) => {
|
|
357
343
|
let didFetchNewSession = false;
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
// validateSession ngecek session-nya beneran ada & "open" enggak,
|
|
370
|
-
// bukan cuma record-nya ada.
|
|
371
|
-
for (const jid of jids) {
|
|
344
|
+
const uniqueJids = [...new Set(jids)];
|
|
345
|
+
const jidsRequiringFetch = [];
|
|
346
|
+
logger.debug({ jids: jids }, "assertSessions call with jids");
|
|
347
|
+
for (const jid of uniqueJids) {
|
|
348
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(jid);
|
|
349
|
+
const cachedSession = peerSessionsCache.get(signalId);
|
|
350
|
+
if (cachedSession !== undefined) {
|
|
351
|
+
if (cachedSession && !force) {
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
} else {
|
|
372
355
|
const sessionValidation = await signalRepository.validateSession(jid);
|
|
373
|
-
|
|
374
|
-
|
|
356
|
+
const hasSession = sessionValidation.exists;
|
|
357
|
+
peerSessionsCache.set(signalId, hasSession);
|
|
358
|
+
if (hasSession && !force) {
|
|
359
|
+
continue;
|
|
375
360
|
}
|
|
376
361
|
}
|
|
362
|
+
jidsRequiringFetch.push(jid);
|
|
377
363
|
}
|
|
378
|
-
|
|
379
364
|
if (jidsRequiringFetch.length) {
|
|
380
|
-
|
|
381
|
-
|
|
365
|
+
const wireJids = [
|
|
366
|
+
...jidsRequiringFetch.filter((jid) => !!isLidUser(jid) || !!isHostedLidUser(jid)),
|
|
367
|
+
...(
|
|
368
|
+
(await signalRepository.lidMapping.getLIDsForPNs(
|
|
369
|
+
jidsRequiringFetch.filter((jid) => !!isPnUser(jid) || !!isHostedPnUser(jid))
|
|
370
|
+
)) || []
|
|
371
|
+
).map((a) => a.lid),
|
|
372
|
+
];
|
|
373
|
+
logger.debug(
|
|
374
|
+
{ jidsRequiringFetch: jidsRequiringFetch, wireJids: wireJids },
|
|
375
|
+
"fetching sessions"
|
|
376
|
+
);
|
|
382
377
|
const result = await query({
|
|
383
|
-
tag:
|
|
384
|
-
attrs: {
|
|
385
|
-
xmlns: 'encrypt',
|
|
386
|
-
type: 'get',
|
|
387
|
-
to: WABinary_1.S_WHATSAPP_NET,
|
|
388
|
-
},
|
|
378
|
+
tag: "iq",
|
|
379
|
+
attrs: { xmlns: "encrypt", type: "get", to: S_WHATSAPP_NET },
|
|
389
380
|
content: [
|
|
390
381
|
{
|
|
391
|
-
tag:
|
|
382
|
+
tag: "key",
|
|
392
383
|
attrs: {},
|
|
393
|
-
content:
|
|
394
|
-
|
|
395
|
-
attrs
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
384
|
+
content: wireJids.map((jid) => {
|
|
385
|
+
const attrs = { jid: jid };
|
|
386
|
+
if (force) attrs.reason = "identity";
|
|
387
|
+
return { tag: "user", attrs: attrs };
|
|
388
|
+
}),
|
|
389
|
+
},
|
|
390
|
+
],
|
|
399
391
|
});
|
|
400
|
-
await
|
|
392
|
+
await parseAndInjectE2ESessions(result, signalRepository);
|
|
401
393
|
didFetchNewSession = true;
|
|
394
|
+
for (const wireJid of wireJids) {
|
|
395
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(wireJid);
|
|
396
|
+
peerSessionsCache.set(signalId, true);
|
|
397
|
+
}
|
|
402
398
|
}
|
|
403
399
|
return didFetchNewSession;
|
|
404
400
|
};
|
|
405
|
-
|
|
406
401
|
const sendPeerDataOperationMessage = async (pdoMessage) => {
|
|
407
402
|
if (!authState.creds.me?.id) {
|
|
408
|
-
throw new
|
|
403
|
+
throw new Boom("Not authenticated");
|
|
409
404
|
}
|
|
410
|
-
|
|
411
405
|
const protocolMessage = {
|
|
412
406
|
protocolMessage: {
|
|
413
407
|
peerDataOperationRequestMessage: pdoMessage,
|
|
414
|
-
type:
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
const meJid = WABinary_1.jidNormalizedUser(authState.creds.me.id)
|
|
419
|
-
const msgId = await relayMessage(meJid, protocolMessage, {
|
|
420
|
-
additionalAttributes: {
|
|
421
|
-
category: 'peer',
|
|
422
|
-
push_priority: 'high_force',
|
|
408
|
+
type: proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE,
|
|
423
409
|
},
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
410
|
+
};
|
|
411
|
+
const meJid = jidNormalizedUser(authState.creds.me.id);
|
|
412
|
+
const msgId = await relayMessage(meJid, protocolMessage, {
|
|
413
|
+
additionalAttributes: { category: "peer", push_priority: "high_force" },
|
|
414
|
+
additionalNodes: [{ tag: "meta", attrs: { appdata: "default" } }],
|
|
415
|
+
});
|
|
416
|
+
return msgId;
|
|
417
|
+
};
|
|
418
|
+
const createParticipantNodes = async (recipientJids, message, extraAttrs, dsmMessage) => {
|
|
419
|
+
if (!recipientJids.length) {
|
|
420
|
+
return { nodes: [], shouldIncludeDeviceIdentity: false };
|
|
433
421
|
}
|
|
434
|
-
|
|
422
|
+
const patched = await patchMessageBeforeSending(message, recipientJids);
|
|
423
|
+
const patchedMessages = Array.isArray(patched)
|
|
424
|
+
? patched
|
|
425
|
+
: recipientJids.map((jid) => ({ recipientJid: jid, message: patched }));
|
|
435
426
|
let shouldIncludeDeviceIdentity = false;
|
|
436
|
-
const
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
427
|
+
const meId = authState.creds.me.id;
|
|
428
|
+
const meLid = authState.creds.me?.lid;
|
|
429
|
+
const meLidUser = meLid ? jidDecode(meLid)?.user : null;
|
|
430
|
+
const encryptionPromises = patchedMessages.map(
|
|
431
|
+
async ({ recipientJid: jid, message: patchedMessage }) => {
|
|
432
|
+
if (!jid) return null;
|
|
433
|
+
let msgToEncrypt = patchedMessage;
|
|
434
|
+
if (dsmMessage) {
|
|
435
|
+
const { user: targetUser } = jidDecode(jid);
|
|
436
|
+
const { user: ownPnUser } = jidDecode(meId);
|
|
437
|
+
const ownLidUser = meLidUser;
|
|
438
|
+
const isOwnUser =
|
|
439
|
+
targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
|
|
440
|
+
const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
|
|
441
|
+
if (isOwnUser && !isExactSenderDevice) {
|
|
442
|
+
msgToEncrypt = dsmMessage;
|
|
443
|
+
logger.debug(
|
|
444
|
+
{ jid: jid, targetUser: targetUser },
|
|
445
|
+
"Using DSM for own device"
|
|
446
|
+
);
|
|
447
|
+
}
|
|
453
448
|
}
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
449
|
+
const bytes = encodeWAMessage(msgToEncrypt);
|
|
450
|
+
const mutexKey = jid;
|
|
451
|
+
const node = await encryptionMutex.mutex(mutexKey, async () => {
|
|
452
|
+
const { type: type, ciphertext: ciphertext } =
|
|
453
|
+
await signalRepository.encryptMessage({ jid: jid, data: bytes });
|
|
454
|
+
if (type === "pkmsg") {
|
|
455
|
+
shouldIncludeDeviceIdentity = true;
|
|
456
|
+
}
|
|
457
|
+
return {
|
|
458
|
+
tag: "to",
|
|
459
|
+
attrs: { jid: jid },
|
|
460
|
+
content: [
|
|
461
|
+
{
|
|
462
|
+
tag: "enc",
|
|
463
|
+
attrs: { v: "2", type: type, ...(extraAttrs || {}) },
|
|
464
|
+
content: ciphertext,
|
|
465
|
+
},
|
|
466
|
+
],
|
|
467
|
+
};
|
|
468
|
+
});
|
|
469
|
+
return node;
|
|
470
|
+
}
|
|
471
|
+
);
|
|
472
|
+
const nodes = (await Promise.all(encryptionPromises)).filter((node) => node !== null);
|
|
473
|
+
return {
|
|
474
|
+
nodes: nodes,
|
|
475
|
+
shouldIncludeDeviceIdentity: shouldIncludeDeviceIdentity,
|
|
476
|
+
};
|
|
471
477
|
};
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
additionalAttributes,
|
|
477
|
-
useUserDevicesCache,
|
|
478
|
-
useCachedGroupMetadata,
|
|
479
|
-
statusJidList,
|
|
480
|
-
additionalNodes,
|
|
481
|
-
ai = false
|
|
482
|
-
}) => {
|
|
483
|
-
const meId = authState.creds.me.id
|
|
484
|
-
const meLid = authState.creds.me?.lid
|
|
485
|
-
|
|
486
|
-
let additionalAlready = false
|
|
487
|
-
let shouldIncludeDeviceIdentity = false
|
|
488
|
-
|
|
489
|
-
const {
|
|
490
|
-
user,
|
|
491
|
-
server
|
|
492
|
-
} = WABinary_1.jidDecode(jid)
|
|
493
|
-
|
|
494
|
-
const statusJid = 'status@broadcast'
|
|
495
|
-
const isGroup = server === 'g.us'
|
|
496
|
-
const isPrivate = server === 's.whatsapp.net'
|
|
497
|
-
const isNewsletter = server == 'newsletter'
|
|
498
|
-
const isStatus = jid === statusJid
|
|
499
|
-
const isLid = server === 'lid'
|
|
500
|
-
|
|
501
|
-
const finalJid = jid
|
|
502
|
-
|
|
503
|
-
let ownId = meId
|
|
504
|
-
|
|
505
|
-
if (isLid && meLid) {
|
|
506
|
-
ownId = meLid
|
|
507
|
-
logger.debug({
|
|
508
|
-
to: jid,
|
|
509
|
-
ownId
|
|
510
|
-
}, 'Using LID identity for @lid conversation')
|
|
478
|
+
const profilePictureUrl = async (jid) => {
|
|
479
|
+
if (isJidNewsletter(jid)) {
|
|
480
|
+
const metadata = await conn.newsletterMetadata("JID", jid);
|
|
481
|
+
return getUrlFromDirectPath(metadata.thread_metadata.picture?.direct_path || "");
|
|
511
482
|
} else {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
483
|
+
const result = await query({
|
|
484
|
+
tag: "iq",
|
|
485
|
+
attrs: {
|
|
486
|
+
target: jidNormalizedUser(jid),
|
|
487
|
+
to: S_WHATSAPP_NET,
|
|
488
|
+
type: "get",
|
|
489
|
+
xmlns: "w:profile:picture",
|
|
490
|
+
},
|
|
491
|
+
content: [{ tag: "picture", attrs: { type: "image", query: "url" } }],
|
|
492
|
+
});
|
|
493
|
+
const child = getBinaryNodeChild(result, "picture");
|
|
494
|
+
return child?.attrs?.url || null;
|
|
516
495
|
}
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
},
|
|
532
|
-
messageContextInfo: message.messageContextInfo || {}
|
|
496
|
+
};
|
|
497
|
+
const relayMessage = async (
|
|
498
|
+
jid,
|
|
499
|
+
message,
|
|
500
|
+
{
|
|
501
|
+
messageId: msgId,
|
|
502
|
+
participant: participant,
|
|
503
|
+
additionalAttributes: additionalAttributes,
|
|
504
|
+
useUserDevicesCache: useUserDevicesCache,
|
|
505
|
+
useCachedGroupMetadata: useCachedGroupMetadata,
|
|
506
|
+
statusJidList: statusJidList,
|
|
507
|
+
additionalNodes: additionalNodes,
|
|
508
|
+
AI: AI = false,
|
|
509
|
+
onTarget = false,
|
|
533
510
|
}
|
|
534
|
-
|
|
535
|
-
const
|
|
536
|
-
const
|
|
537
|
-
const
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
511
|
+
) => {
|
|
512
|
+
const meId = authState.creds.me.id;
|
|
513
|
+
const meLid = authState.creds.me?.lid;
|
|
514
|
+
const isRetryResend = Boolean(participant?.jid);
|
|
515
|
+
let shouldIncludeDeviceIdentity = isRetryResend;
|
|
516
|
+
let didPushAdditional = false;
|
|
517
|
+
const statusJid = "status@broadcast";
|
|
518
|
+
const { user: user, server: server } = jidDecode(jid);
|
|
519
|
+
const isGroup = server === "g.us";
|
|
520
|
+
const isStatus = jid === statusJid;
|
|
521
|
+
const isLid = server === "lid";
|
|
522
|
+
const isNewsletter = server === "newsletter";
|
|
523
|
+
const isGroupOrStatus = isGroup || isStatus;
|
|
524
|
+
const finalJid = jid;
|
|
525
|
+
msgId = msgId || generateMessageID(meId);
|
|
526
|
+
useUserDevicesCache = useUserDevicesCache !== false;
|
|
527
|
+
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus;
|
|
528
|
+
const participants = [];
|
|
529
|
+
const destinationJid = !isStatus ? finalJid : statusJid;
|
|
530
|
+
const binaryNodeContent = [];
|
|
531
|
+
const devices = [];
|
|
532
|
+
const meMsg = {
|
|
533
|
+
deviceSentMessage: { destinationJid: destinationJid, message: message },
|
|
534
|
+
messageContextInfo: message.messageContextInfo,
|
|
535
|
+
};
|
|
536
|
+
const extraAttrs = {};
|
|
537
|
+
const regexGroupOld = /^(\d{1,15})-(\d+)@g\.us$/;
|
|
538
|
+
const messages = normalizeMessageContent(message);
|
|
539
|
+
const buttonType = getButtonType(messages);
|
|
540
|
+
const pollMessage =
|
|
541
|
+
messages.pollCreationMessage ||
|
|
542
|
+
messages.pollCreationMessageV2 ||
|
|
543
|
+
messages.pollCreationMessageV3;
|
|
541
544
|
if (participant) {
|
|
542
545
|
if (!isGroup && !isStatus) {
|
|
543
546
|
additionalAttributes = {
|
|
544
547
|
...additionalAttributes,
|
|
545
|
-
|
|
546
|
-
}
|
|
548
|
+
device_fanout: "false",
|
|
549
|
+
};
|
|
547
550
|
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
user,
|
|
551
|
-
device
|
|
552
|
-
} = WABinary_1.jidDecode(participant.jid)
|
|
553
|
-
|
|
554
|
-
devices.push({
|
|
555
|
-
user,
|
|
556
|
-
device,
|
|
557
|
-
wireJid: participant.jid
|
|
558
|
-
})
|
|
551
|
+
const { user: user, device: device } = jidDecode(participant.jid);
|
|
552
|
+
devices.push({ user: user, device: device, jid: participant.jid });
|
|
559
553
|
}
|
|
560
|
-
|
|
561
554
|
await authState.keys.transaction(async () => {
|
|
562
|
-
const mediaType = getMediaType(
|
|
555
|
+
const mediaType = getMediaType(message);
|
|
563
556
|
if (mediaType) {
|
|
564
|
-
extraAttrs[
|
|
557
|
+
extraAttrs["mediatype"] = mediaType;
|
|
565
558
|
}
|
|
559
|
+
if (isNewsletter) {
|
|
566
560
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
561
|
+
const patched = patchMessageBeforeSending
|
|
562
|
+
? await patchMessageBeforeSending(message, [])
|
|
563
|
+
: message
|
|
564
|
+
|
|
565
|
+
const mediaType = getMediaType(patched)
|
|
566
|
+
|
|
567
|
+
if (mediaType) {
|
|
568
|
+
extraAttrs["mediatype"] = mediaType
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
if (
|
|
572
|
+
patched.interactiveMessage &&
|
|
573
|
+
!extraAttrs["mediatype"]
|
|
574
|
+
) {
|
|
575
|
+
extraAttrs["mediatype"] = "interactive"
|
|
576
|
+
}
|
|
570
577
|
|
|
578
|
+
const bytes = encodeNewsletterMessage(patched)
|
|
579
|
+
|
|
580
|
+
binaryNodeContent.push({
|
|
581
|
+
tag: "plaintext",
|
|
582
|
+
attrs: extraAttrs,
|
|
583
|
+
content: bytes
|
|
584
|
+
})
|
|
585
|
+
|
|
586
|
+
const stanza = {
|
|
587
|
+
tag: "message",
|
|
588
|
+
attrs: {
|
|
589
|
+
to: jid,
|
|
590
|
+
id: msgId,
|
|
591
|
+
type: getTypeMessage(patched),
|
|
592
|
+
...(additionalAttributes || {}),
|
|
593
|
+
},
|
|
594
|
+
content: binaryNodeContent,
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
logger.debug(
|
|
598
|
+
{
|
|
599
|
+
msgId,
|
|
600
|
+
mediaType,
|
|
601
|
+
extraAttrs
|
|
602
|
+
},
|
|
603
|
+
`sending newsletter message to ${jid}`
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
await sendNode(stanza)
|
|
607
|
+
|
|
608
|
+
return
|
|
609
|
+
}
|
|
610
|
+
if (
|
|
611
|
+
messages.pinInChatMessage ||
|
|
612
|
+
messages.keepInChatMessage ||
|
|
613
|
+
message.reactionMessage ||
|
|
614
|
+
message.protocolMessage?.editedMessage
|
|
615
|
+
) {
|
|
616
|
+
extraAttrs["decrypt-fail"] = "hide";
|
|
617
|
+
}
|
|
571
618
|
if (messages.interactiveResponseMessage?.nativeFlowResponseMessage) {
|
|
572
|
-
extraAttrs[
|
|
619
|
+
extraAttrs["native_flow_name"] =
|
|
620
|
+
messages.interactiveResponseMessage.nativeFlowResponseMessage?.name ||
|
|
621
|
+
"menu_options";
|
|
573
622
|
}
|
|
574
|
-
|
|
575
|
-
if (isGroup || isStatus) {
|
|
623
|
+
if (isGroupOrStatus && !isRetryResend) {
|
|
576
624
|
const [groupData, senderKeyMap] = await Promise.all([
|
|
577
625
|
(async () => {
|
|
578
|
-
let groupData =
|
|
626
|
+
let groupData =
|
|
627
|
+
useCachedGroupMetadata && cachedGroupMetadata
|
|
628
|
+
? await cachedGroupMetadata(jid)
|
|
629
|
+
: undefined;
|
|
579
630
|
if (groupData && Array.isArray(groupData?.participants)) {
|
|
580
|
-
logger.trace(
|
|
581
|
-
jid,
|
|
582
|
-
|
|
583
|
-
|
|
631
|
+
logger.trace(
|
|
632
|
+
{ jid: jid, participants: groupData.participants.length },
|
|
633
|
+
"using cached group metadata"
|
|
634
|
+
);
|
|
584
635
|
} else if (!isStatus) {
|
|
585
|
-
groupData = await
|
|
636
|
+
groupData = await groupMetadata(jid);
|
|
586
637
|
}
|
|
587
|
-
return groupData
|
|
638
|
+
return groupData;
|
|
588
639
|
})(),
|
|
589
640
|
(async () => {
|
|
590
641
|
if (!participant && !isStatus) {
|
|
591
|
-
const result = await authState.keys.get(
|
|
592
|
-
return result[jid] || {}
|
|
642
|
+
const result = await authState.keys.get("sender-key-memory", [jid]);
|
|
643
|
+
return result[jid] || {};
|
|
593
644
|
}
|
|
594
|
-
return {}
|
|
595
|
-
})()
|
|
596
|
-
])
|
|
597
|
-
|
|
598
|
-
if (
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
}
|
|
603
|
-
if (!isStatus) {
|
|
604
|
-
const groupAddressingMode = groupData?.addressingMode || (isLid ? Types_1.WAMessageAddressingMode.LID : Types_1.WAMessageAddressingMode.PN)
|
|
605
|
-
additionalAttributes = {
|
|
606
|
-
...additionalAttributes,
|
|
607
|
-
addressing_mode: groupAddressingMode
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false)
|
|
611
|
-
devices.push(...additionalDevices)
|
|
645
|
+
return {};
|
|
646
|
+
})(),
|
|
647
|
+
]);
|
|
648
|
+
const participantsList = groupData ? groupData.participants.map((p) => p.id) : [];
|
|
649
|
+
if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
|
|
650
|
+
additionalAttributes = {
|
|
651
|
+
...additionalAttributes,
|
|
652
|
+
expiration: groupData.ephemeralDuration.toString(),
|
|
653
|
+
};
|
|
612
654
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
655
|
+
if (isStatus && statusJidList) {
|
|
656
|
+
participantsList.push(...statusJidList);
|
|
657
|
+
}
|
|
658
|
+
const additionalDevices = await getUSyncDevices(
|
|
659
|
+
participantsList,
|
|
660
|
+
!!useUserDevicesCache,
|
|
661
|
+
false
|
|
662
|
+
);
|
|
663
|
+
devices.push(...additionalDevices);
|
|
664
|
+
if (isGroup) {
|
|
665
|
+
additionalAttributes = {
|
|
666
|
+
...additionalAttributes,
|
|
667
|
+
addressing_mode: groupData?.addressingMode || "lid",
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
const patched = await patchMessageBeforeSending(message);
|
|
671
|
+
if (Array.isArray(patched)) {
|
|
672
|
+
throw new Boom("Per-jid patching is not supported in groups");
|
|
673
|
+
}
|
|
674
|
+
const bytes = encodeWAMessage(patched);
|
|
675
|
+
const groupAddressingMode =
|
|
676
|
+
additionalAttributes?.["addressing_mode"] || groupData?.addressingMode || "lid";
|
|
677
|
+
const groupSenderIdentity = groupAddressingMode === "lid" && meLid ? meLid : meId;
|
|
620
678
|
const {
|
|
621
|
-
ciphertext,
|
|
622
|
-
senderKeyDistributionMessage
|
|
679
|
+
ciphertext: ciphertext,
|
|
680
|
+
senderKeyDistributionMessage: senderKeyDistributionMessage,
|
|
623
681
|
} = await signalRepository.encryptGroupMessage({
|
|
624
682
|
group: destinationJid,
|
|
625
683
|
data: bytes,
|
|
626
|
-
meId: groupSenderIdentity
|
|
627
|
-
})
|
|
628
|
-
|
|
629
|
-
const senderKeyJids = []
|
|
630
|
-
|
|
684
|
+
meId: groupSenderIdentity,
|
|
685
|
+
});
|
|
686
|
+
const senderKeyRecipients = [];
|
|
631
687
|
for (const device of devices) {
|
|
632
|
-
const deviceJid = device.
|
|
633
|
-
const hasKey = !!senderKeyMap[deviceJid]
|
|
634
|
-
if (
|
|
635
|
-
|
|
636
|
-
|
|
688
|
+
const deviceJid = device.jid;
|
|
689
|
+
const hasKey = !!senderKeyMap[deviceJid];
|
|
690
|
+
if (
|
|
691
|
+
(!hasKey || !!participant) &&
|
|
692
|
+
!isHostedLidUser(deviceJid) &&
|
|
693
|
+
!isHostedPnUser(deviceJid) &&
|
|
694
|
+
device.device !== 99
|
|
695
|
+
) {
|
|
696
|
+
senderKeyRecipients.push(deviceJid);
|
|
697
|
+
senderKeyMap[deviceJid] = true;
|
|
637
698
|
}
|
|
638
699
|
}
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
logger.debug({
|
|
642
|
-
senderKeyJids
|
|
643
|
-
}, 'sending new sender key')
|
|
700
|
+
if (senderKeyRecipients.length) {
|
|
701
|
+
logger.debug({ senderKeyJids: senderKeyRecipients }, "sending new sender key");
|
|
644
702
|
const senderKeyMsg = {
|
|
645
703
|
senderKeyDistributionMessage: {
|
|
646
704
|
axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
|
|
647
|
-
groupId: destinationJid
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
await assertSessions(
|
|
652
|
-
const result = await createParticipantNodes(
|
|
653
|
-
|
|
654
|
-
|
|
705
|
+
groupId: destinationJid,
|
|
706
|
+
},
|
|
707
|
+
};
|
|
708
|
+
const senderKeySessionTargets = senderKeyRecipients;
|
|
709
|
+
await assertSessions(senderKeySessionTargets);
|
|
710
|
+
const result = await createParticipantNodes(
|
|
711
|
+
senderKeyRecipients,
|
|
712
|
+
senderKeyMsg,
|
|
713
|
+
extraAttrs
|
|
714
|
+
);
|
|
715
|
+
shouldIncludeDeviceIdentity =
|
|
716
|
+
shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity;
|
|
717
|
+
participants.push(...result.nodes);
|
|
655
718
|
}
|
|
656
|
-
|
|
657
719
|
binaryNodeContent.push({
|
|
658
|
-
tag:
|
|
659
|
-
attrs: {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
...extraAttrs
|
|
663
|
-
},
|
|
664
|
-
content: ciphertext
|
|
665
|
-
})
|
|
666
|
-
|
|
720
|
+
tag: "enc",
|
|
721
|
+
attrs: { v: "2", type: "skmsg", ...extraAttrs },
|
|
722
|
+
content: ciphertext,
|
|
723
|
+
});
|
|
667
724
|
await authState.keys.set({
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
}
|
|
671
|
-
})
|
|
672
|
-
} else if (isNewsletter) {
|
|
673
|
-
if (message.protocolMessage?.editedMessage) {
|
|
674
|
-
msgId = message.protocolMessage.key?.id
|
|
675
|
-
message = message.protocolMessage.editedMessage
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
if (message.protocolMessage?.type === WAProto_1.proto.Message.ProtocolMessage.Type.REVOKE) {
|
|
679
|
-
msgId = message.protocolMessage.key?.id
|
|
680
|
-
message = {}
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
const patched = await patchMessageBeforeSending(message, [])
|
|
684
|
-
const bytes = Utils_1.encodeNewsletterMessage(patched)
|
|
685
|
-
|
|
686
|
-
binaryNodeContent.push({
|
|
687
|
-
tag: 'plaintext',
|
|
688
|
-
attrs: extraAttrs,
|
|
689
|
-
content: bytes
|
|
690
|
-
})
|
|
725
|
+
"sender-key-memory": { [jid]: senderKeyMap },
|
|
726
|
+
});
|
|
691
727
|
} else {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
728
|
+
let ownId = meId;
|
|
729
|
+
if (isLid && meLid) {
|
|
730
|
+
ownId = meLid;
|
|
731
|
+
logger.debug(
|
|
732
|
+
{ to: jid, ownId: ownId },
|
|
733
|
+
"Using LID identity for @lid conversation"
|
|
734
|
+
);
|
|
735
|
+
} else {
|
|
736
|
+
logger.debug(
|
|
737
|
+
{ to: jid, ownId: ownId },
|
|
738
|
+
"Using PN identity for @s.whatsapp.net conversation"
|
|
739
|
+
);
|
|
740
|
+
}
|
|
741
|
+
const { user: ownUser } = jidDecode(ownId);
|
|
742
|
+
if (!isRetryResend) {
|
|
743
|
+
const targetUserServer = isLid ? "lid" : "s.whatsapp.net";
|
|
698
744
|
devices.push({
|
|
699
|
-
user,
|
|
745
|
+
user: user,
|
|
700
746
|
device: 0,
|
|
701
|
-
|
|
702
|
-
})
|
|
703
|
-
|
|
747
|
+
jid: jidEncode(user, targetUserServer, 0),
|
|
748
|
+
});
|
|
704
749
|
if (user !== ownUser) {
|
|
705
|
-
const ownUserServer = isLid ?
|
|
706
|
-
const ownUserForAddressing =
|
|
750
|
+
const ownUserServer = isLid ? "lid" : "s.whatsapp.net";
|
|
751
|
+
const ownUserForAddressing =
|
|
752
|
+
isLid && meLid ? jidDecode(meLid).user : jidDecode(meId).user;
|
|
707
753
|
devices.push({
|
|
708
754
|
user: ownUserForAddressing,
|
|
709
755
|
device: 0,
|
|
710
|
-
|
|
711
|
-
})
|
|
756
|
+
jid: jidEncode(ownUserForAddressing, ownUserServer, 0),
|
|
757
|
+
});
|
|
712
758
|
}
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
759
|
+
if (additionalAttributes?.["category"] !== "peer") {
|
|
760
|
+
devices.length = 0;
|
|
761
|
+
const senderIdentity =
|
|
762
|
+
isLid && meLid
|
|
763
|
+
? jidEncode(jidDecode(meLid)?.user, "lid", undefined)
|
|
764
|
+
: jidEncode(jidDecode(meId)?.user, "s.whatsapp.net", undefined);
|
|
765
|
+
const sessionDevices = await getUSyncDevices(
|
|
766
|
+
[senderIdentity, jid],
|
|
767
|
+
true,
|
|
768
|
+
false
|
|
769
|
+
);
|
|
770
|
+
devices.push(...sessionDevices);
|
|
771
|
+
logger.debug(
|
|
772
|
+
{
|
|
773
|
+
deviceCount: devices.length,
|
|
774
|
+
devices: devices.map(
|
|
775
|
+
(d) => `${d.user}:${d.device}@${jidDecode(d.jid)?.server}`
|
|
776
|
+
),
|
|
777
|
+
},
|
|
778
|
+
"Device enumeration complete with unified addressing"
|
|
779
|
+
);
|
|
723
780
|
}
|
|
724
781
|
}
|
|
782
|
+
const allRecipients = []
|
|
783
|
+
const meRecipients = []
|
|
784
|
+
const otherRecipients = []
|
|
785
|
+
|
|
786
|
+
const { user: mePnUser } = jidDecode(meId)
|
|
787
|
+
const { user: meLidUser } = meLid ? jidDecode(meLid) : { user: null }
|
|
788
|
+
|
|
789
|
+
for (const { user, jid } of devices) {
|
|
790
|
+
const isExactSenderDevice =
|
|
791
|
+
jid === meId || (meLid && jid === meLid)
|
|
792
|
+
|
|
793
|
+
if (isExactSenderDevice) {
|
|
794
|
+
logger.debug(
|
|
795
|
+
{ jid, meId, meLid },
|
|
796
|
+
'Skipping exact sender device (whatsmeow pattern)'
|
|
797
|
+
)
|
|
798
|
+
continue
|
|
799
|
+
}
|
|
725
800
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
const {
|
|
731
|
-
user: mePnUser
|
|
732
|
-
} = WABinary_1.jidDecode(meId)
|
|
733
|
-
const {
|
|
734
|
-
user: meLidUser
|
|
735
|
-
} = meLid ? WABinary_1.jidDecode(meLid) : {
|
|
736
|
-
user: null
|
|
737
|
-
}
|
|
801
|
+
const isMe =
|
|
802
|
+
user === mePnUser ||
|
|
803
|
+
user === meLidUser
|
|
738
804
|
|
|
739
|
-
|
|
740
|
-
const isExactSenderDevice = wireJid === meId || (meLid && wireJid === meLid)
|
|
741
|
-
if (isExactSenderDevice) {
|
|
742
|
-
logger.debug({
|
|
743
|
-
wireJid,
|
|
744
|
-
meId,
|
|
745
|
-
meLid
|
|
746
|
-
}, 'Skipping exact sender device (whatsmeow pattern)')
|
|
747
|
-
continue
|
|
748
|
-
}
|
|
749
|
-
const isMe = user === mePnUser || (meLidUser && user === meLidUser)
|
|
750
|
-
const jid = wireJid
|
|
751
|
-
if (isMe) {
|
|
752
|
-
meJids.push(jid)
|
|
753
|
-
} else {
|
|
754
|
-
otherJids.push(jid)
|
|
755
|
-
}
|
|
756
|
-
allJids.push(jid)
|
|
757
|
-
}
|
|
805
|
+
const skipSender = onTarget === true
|
|
758
806
|
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
}] = await Promise.all([
|
|
767
|
-
createParticipantNodes(meJids, meMsg || message, extraAttrs),
|
|
768
|
-
createParticipantNodes(otherJids, message, extraAttrs, meMsg)
|
|
769
|
-
])
|
|
807
|
+
if (isMe) {
|
|
808
|
+
if (!skipSender) {
|
|
809
|
+
meRecipients.push(jid)
|
|
810
|
+
allRecipients.push(jid)
|
|
811
|
+
}
|
|
812
|
+
continue
|
|
813
|
+
}
|
|
770
814
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
815
|
+
otherRecipients.push(jid)
|
|
816
|
+
allRecipients.push(jid)
|
|
817
|
+
}
|
|
818
|
+
await assertSessions(allRecipients);
|
|
819
|
+
const [
|
|
820
|
+
{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 },
|
|
821
|
+
{ nodes: otherNodes, shouldIncludeDeviceIdentity: s2 },
|
|
822
|
+
] = await Promise.all([
|
|
823
|
+
createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
|
|
824
|
+
createParticipantNodes(otherRecipients, message, extraAttrs, meMsg),
|
|
825
|
+
]);
|
|
826
|
+
participants.push(...meNodes);
|
|
827
|
+
participants.push(...otherNodes);
|
|
828
|
+
if (meRecipients.length > 0 || otherRecipients.length > 0) {
|
|
829
|
+
extraAttrs["phash"] = generateParticipantHashV2([
|
|
830
|
+
...meRecipients,
|
|
831
|
+
...otherRecipients,
|
|
832
|
+
]);
|
|
775
833
|
}
|
|
776
|
-
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2
|
|
834
|
+
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2;
|
|
835
|
+
}
|
|
836
|
+
if (isRetryResend) {
|
|
837
|
+
const isParticipantLid = isLidUser(participant.jid);
|
|
838
|
+
const isMe = areJidsSameUser(participant.jid, isParticipantLid ? meLid : meId);
|
|
839
|
+
const encodedMessageToSend = isMe
|
|
840
|
+
? encodeWAMessage({
|
|
841
|
+
deviceSentMessage: {
|
|
842
|
+
destinationJid: destinationJid,
|
|
843
|
+
message: message,
|
|
844
|
+
},
|
|
845
|
+
})
|
|
846
|
+
: encodeWAMessage(message);
|
|
847
|
+
const { type: type, ciphertext: encryptedContent } =
|
|
848
|
+
await signalRepository.encryptMessage({
|
|
849
|
+
data: encodedMessageToSend,
|
|
850
|
+
jid: participant.jid,
|
|
851
|
+
});
|
|
852
|
+
binaryNodeContent.push({
|
|
853
|
+
tag: "enc",
|
|
854
|
+
attrs: { v: "2", type: type, count: participant.count.toString() },
|
|
855
|
+
content: encryptedContent,
|
|
856
|
+
});
|
|
777
857
|
}
|
|
778
|
-
|
|
779
858
|
if (participants.length) {
|
|
780
|
-
if (additionalAttributes?.[
|
|
781
|
-
const peerNode = participants[0]?.content?.[0]
|
|
859
|
+
if (additionalAttributes?.["category"] === "peer") {
|
|
860
|
+
const peerNode = participants[0]?.content?.[0];
|
|
782
861
|
if (peerNode) {
|
|
783
|
-
binaryNodeContent.push(peerNode)
|
|
862
|
+
binaryNodeContent.push(peerNode);
|
|
784
863
|
}
|
|
785
864
|
} else {
|
|
786
865
|
binaryNodeContent.push({
|
|
787
|
-
tag:
|
|
866
|
+
tag: "participants",
|
|
788
867
|
attrs: {},
|
|
789
|
-
content: participants
|
|
790
|
-
})
|
|
868
|
+
content: participants,
|
|
869
|
+
});
|
|
791
870
|
}
|
|
792
871
|
}
|
|
793
|
-
|
|
794
872
|
const stanza = {
|
|
795
|
-
tag:
|
|
873
|
+
tag: "message",
|
|
796
874
|
attrs: {
|
|
797
|
-
to: destinationJid,
|
|
798
875
|
id: msgId,
|
|
876
|
+
to: destinationJid,
|
|
799
877
|
type: getTypeMessage(message),
|
|
800
|
-
...(additionalAttributes || {})
|
|
878
|
+
...(additionalAttributes || {}),
|
|
801
879
|
},
|
|
802
|
-
content: binaryNodeContent
|
|
803
|
-
}
|
|
804
|
-
|
|
880
|
+
content: binaryNodeContent,
|
|
881
|
+
};
|
|
805
882
|
if (participant) {
|
|
806
|
-
if (
|
|
807
|
-
stanza.attrs.to = destinationJid
|
|
808
|
-
stanza.attrs.participant = participant.jid
|
|
809
|
-
} else if (
|
|
810
|
-
stanza.attrs.to = participant.jid
|
|
811
|
-
stanza.attrs.recipient = destinationJid
|
|
883
|
+
if (isJidGroup(destinationJid)) {
|
|
884
|
+
stanza.attrs.to = destinationJid;
|
|
885
|
+
stanza.attrs.participant = participant.jid;
|
|
886
|
+
} else if (areJidsSameUser(participant.jid, meId)) {
|
|
887
|
+
stanza.attrs.to = participant.jid;
|
|
888
|
+
stanza.attrs.recipient = destinationJid;
|
|
812
889
|
} else {
|
|
813
|
-
stanza.attrs.to = participant.jid
|
|
890
|
+
stanza.attrs.to = participant.jid;
|
|
814
891
|
}
|
|
815
892
|
} else {
|
|
816
|
-
stanza.attrs.to = destinationJid
|
|
893
|
+
stanza.attrs.to = destinationJid;
|
|
817
894
|
}
|
|
818
|
-
|
|
819
895
|
if (shouldIncludeDeviceIdentity) {
|
|
820
896
|
stanza.content.push({
|
|
821
|
-
tag:
|
|
897
|
+
tag: "device-identity",
|
|
822
898
|
attrs: {},
|
|
823
|
-
content:
|
|
824
|
-
})
|
|
825
|
-
logger.debug({
|
|
826
|
-
jid
|
|
827
|
-
}, 'adding device identity')
|
|
899
|
+
content: encodeSignedDeviceIdentity(authState.creds.account, true),
|
|
900
|
+
});
|
|
901
|
+
logger.debug({ jid: jid }, "adding device identity");
|
|
828
902
|
}
|
|
829
|
-
|
|
830
|
-
|
|
903
|
+
const contactTcTokenData =
|
|
904
|
+
!isGroup && !isRetryResend && !isStatus
|
|
905
|
+
? await authState.keys.get("tctoken", [destinationJid])
|
|
906
|
+
: {};
|
|
907
|
+
const tcTokenBuffer = contactTcTokenData[destinationJid]?.token;
|
|
908
|
+
if (tcTokenBuffer) {
|
|
831
909
|
stanza.content.push({
|
|
832
|
-
tag:
|
|
833
|
-
attrs: {}
|
|
834
|
-
|
|
910
|
+
tag: "tctoken",
|
|
911
|
+
attrs: {},
|
|
912
|
+
content: tcTokenBuffer,
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
if (isGroup && regexGroupOld.test(jid) && !message.reactionMessage) {
|
|
916
|
+
stanza.content.push({ tag: "multicast", attrs: {} });
|
|
835
917
|
}
|
|
836
|
-
|
|
837
918
|
if (pollMessage || messages.eventMessage) {
|
|
838
|
-
let attrs = {};
|
|
839
|
-
if (messages.eventMessage) {
|
|
840
|
-
attrs.event_type = 'creation';
|
|
841
|
-
} else {
|
|
842
|
-
attrs.polltype = 'creation';
|
|
843
|
-
if (isNewsletter) {
|
|
844
|
-
attrs.contenttype = (pollMessage && pollMessage.pollContentType === 2) ? 'image' : 'text';
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
919
|
stanza.content.push({
|
|
848
|
-
tag:
|
|
849
|
-
attrs:
|
|
920
|
+
tag: "meta",
|
|
921
|
+
attrs: messages.eventMessage
|
|
922
|
+
? { event_type: "creation" }
|
|
923
|
+
: isNewsletter
|
|
924
|
+
? {
|
|
925
|
+
polltype: "creation",
|
|
926
|
+
contenttype: pollMessage?.pollContentType === 2 ? "image" : "text",
|
|
927
|
+
}
|
|
928
|
+
: { polltype: "creation" },
|
|
850
929
|
});
|
|
851
930
|
}
|
|
852
|
-
|
|
853
931
|
if (!isNewsletter && buttonType) {
|
|
854
|
-
const buttonsNode = getButtonArgs(messages)
|
|
855
|
-
const filteredButtons =
|
|
932
|
+
const buttonsNode = getButtonArgs(messages);
|
|
933
|
+
const filteredButtons = getBinaryFilteredButtons(
|
|
934
|
+
additionalNodes ? additionalNodes : []
|
|
935
|
+
);
|
|
856
936
|
if (filteredButtons) {
|
|
857
|
-
stanza.content.push(...additionalNodes)
|
|
858
|
-
|
|
937
|
+
stanza.content.push(...additionalNodes);
|
|
938
|
+
didPushAdditional = true;
|
|
859
939
|
} else {
|
|
860
|
-
stanza.content.push(buttonsNode)
|
|
940
|
+
stanza.content.push(buttonsNode);
|
|
861
941
|
}
|
|
862
942
|
}
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
const
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
biz_bot: '1'
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
|
-
const filteredBizBot = WABinary_1.getBinaryFilteredBizBot(additionalNodes ? additionalNodes : [])
|
|
943
|
+
if (AI && isPrivate) {
|
|
944
|
+
const botNode = { tag: "bot", attrs: { biz_bot: "1" } };
|
|
945
|
+
const filteredBizBot = getBinaryFilteredBizBot(
|
|
946
|
+
additionalNodes ? additionalNodes : []
|
|
947
|
+
);
|
|
872
948
|
if (filteredBizBot) {
|
|
873
|
-
stanza.content.push(...additionalNodes)
|
|
874
|
-
|
|
949
|
+
stanza.content.push(...additionalNodes);
|
|
950
|
+
didPushAdditional = true;
|
|
875
951
|
} else {
|
|
876
|
-
stanza.content.push(botNode)
|
|
952
|
+
stanza.content.push(botNode);
|
|
877
953
|
}
|
|
878
954
|
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
stanza.content.push(...additionalNodes)
|
|
955
|
+
if (!didPushAdditional && additionalNodes && additionalNodes.length > 0) {
|
|
956
|
+
stanza.content.push(...additionalNodes);
|
|
882
957
|
}
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
msgId
|
|
886
|
-
}, `sending message to ${participants.length} devices`)
|
|
887
|
-
|
|
888
|
-
await sendNode(stanza)
|
|
958
|
+
logger.debug({ msgId: msgId }, `sending message to ${participants.length} devices`);
|
|
959
|
+
await sendNode(stanza);
|
|
889
960
|
if (messageRetryManager && !participant) {
|
|
890
|
-
messageRetryManager.addRecentMessage(destinationJid, msgId, message)
|
|
961
|
+
messageRetryManager.addRecentMessage(destinationJid, msgId, message);
|
|
891
962
|
}
|
|
892
|
-
}, meId)
|
|
893
|
-
return msgId
|
|
894
|
-
}
|
|
895
|
-
|
|
963
|
+
}, meId);
|
|
964
|
+
return msgId;
|
|
965
|
+
};
|
|
896
966
|
const getTypeMessage = (msg) => {
|
|
897
|
-
const message =
|
|
898
|
-
if (
|
|
899
|
-
|
|
967
|
+
const message = normalizeMessageContent(msg);
|
|
968
|
+
if (
|
|
969
|
+
message.pollCreationMessage ||
|
|
970
|
+
message.pollCreationMessageV2 ||
|
|
971
|
+
message.pollCreationMessageV3
|
|
972
|
+
) {
|
|
973
|
+
return "poll";
|
|
900
974
|
} else if (message.reactionMessage) {
|
|
901
|
-
return
|
|
975
|
+
return "reaction";
|
|
902
976
|
} else if (message.eventMessage) {
|
|
903
|
-
return
|
|
977
|
+
return "event";
|
|
904
978
|
} else if (getMediaType(message)) {
|
|
905
|
-
return
|
|
979
|
+
return "media";
|
|
906
980
|
} else {
|
|
907
|
-
return
|
|
981
|
+
return "text";
|
|
908
982
|
}
|
|
909
|
-
}
|
|
910
|
-
|
|
983
|
+
};
|
|
911
984
|
const getMediaType = (message) => {
|
|
912
985
|
if (message.imageMessage) {
|
|
913
|
-
return
|
|
986
|
+
return "image";
|
|
914
987
|
} else if (message.stickerMessage) {
|
|
915
|
-
return message.stickerMessage.isLottie
|
|
988
|
+
return message.stickerMessage.isLottie
|
|
989
|
+
? "1p_sticker"
|
|
990
|
+
: message.stickerMessage.isAvatar
|
|
991
|
+
? "avatar_sticker"
|
|
992
|
+
: "sticker";
|
|
916
993
|
} else if (message.videoMessage) {
|
|
917
|
-
return message.videoMessage.gifPlayback ?
|
|
994
|
+
return message.videoMessage.gifPlayback ? "gif" : "video";
|
|
918
995
|
} else if (message.audioMessage) {
|
|
919
|
-
return message.audioMessage.ptt ?
|
|
996
|
+
return message.audioMessage.ptt ? "ptt" : "audio";
|
|
920
997
|
} else if (message.ptvMessage) {
|
|
921
|
-
return
|
|
998
|
+
return "ptv";
|
|
922
999
|
} else if (message.albumMessage) {
|
|
923
|
-
return
|
|
1000
|
+
return "collection";
|
|
924
1001
|
} else if (message.contactMessage) {
|
|
925
|
-
return
|
|
1002
|
+
return "vcard";
|
|
926
1003
|
} else if (message.documentMessage) {
|
|
927
|
-
return
|
|
1004
|
+
return "document";
|
|
928
1005
|
} else if (message.stickerPackMessage) {
|
|
929
|
-
return
|
|
1006
|
+
return "sticker_pack";
|
|
930
1007
|
} else if (message.contactsArrayMessage) {
|
|
931
|
-
return
|
|
1008
|
+
return "contact_array";
|
|
932
1009
|
} else if (message.locationMessage) {
|
|
933
|
-
return
|
|
1010
|
+
return "location";
|
|
934
1011
|
} else if (message.liveLocationMessage) {
|
|
935
|
-
return
|
|
1012
|
+
return "livelocation";
|
|
936
1013
|
} else if (message.listMessage) {
|
|
937
|
-
return
|
|
1014
|
+
return "list";
|
|
938
1015
|
} else if (message.listResponseMessage) {
|
|
939
|
-
return
|
|
1016
|
+
return "list_response";
|
|
940
1017
|
} else if (message.buttonsResponseMessage) {
|
|
941
|
-
return
|
|
1018
|
+
return "buttons_response";
|
|
942
1019
|
} else if (message.orderMessage) {
|
|
943
|
-
return
|
|
1020
|
+
return "order";
|
|
944
1021
|
} else if (message.productMessage) {
|
|
945
|
-
return
|
|
1022
|
+
return "product";
|
|
946
1023
|
} else if (message.interactiveResponseMessage) {
|
|
947
|
-
return
|
|
1024
|
+
return "native_flow_response";
|
|
948
1025
|
} else if (/https:\/\/wa\.me\/c\/\d+/.test(message.extendedTextMessage?.text)) {
|
|
949
|
-
return
|
|
1026
|
+
return "cataloglink";
|
|
950
1027
|
} else if (/https:\/\/wa\.me\/p\/\d+\/\d+/.test(message.extendedTextMessage?.text)) {
|
|
951
|
-
return
|
|
1028
|
+
return "productlink";
|
|
952
1029
|
} else if (message.extendedTextMessage?.matchedText || message.groupInviteMessage) {
|
|
953
|
-
return
|
|
1030
|
+
return "url";
|
|
954
1031
|
}
|
|
955
|
-
}
|
|
956
|
-
|
|
1032
|
+
};
|
|
957
1033
|
const getButtonType = (message) => {
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
return 'native_flow';
|
|
1034
|
+
if (message.listMessage) {
|
|
1035
|
+
return "list";
|
|
1036
|
+
} else if (message.buttonsMessage) {
|
|
1037
|
+
return "buttons";
|
|
1038
|
+
} else if (message.interactiveMessage?.nativeFlowMessage) {
|
|
1039
|
+
return "native_flow";
|
|
965
1040
|
}
|
|
966
1041
|
};
|
|
967
|
-
|
|
968
1042
|
const getButtonArgs = (message) => {
|
|
969
|
-
const
|
|
970
|
-
const
|
|
971
|
-
const
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1043
|
+
const nativeFlow = message.interactiveMessage?.nativeFlowMessage;
|
|
1044
|
+
const firstButtonName = nativeFlow?.buttons?.[0]?.name;
|
|
1045
|
+
const nativeFlowSpecials = [
|
|
1046
|
+
"mpm",
|
|
1047
|
+
"cta_catalog",
|
|
1048
|
+
"send_location",
|
|
1049
|
+
"call_permission_request",
|
|
1050
|
+
"wa_payment_transaction_details",
|
|
1051
|
+
"automated_greeting_message_view_catalog",
|
|
1052
|
+
];
|
|
1053
|
+
if (
|
|
1054
|
+
nativeFlow &&
|
|
1055
|
+
(firstButtonName === "review_and_pay" || firstButtonName === "payment_info")
|
|
1056
|
+
) {
|
|
982
1057
|
return {
|
|
983
|
-
tag:
|
|
1058
|
+
tag: "biz",
|
|
984
1059
|
attrs: {
|
|
985
|
-
native_flow_name:
|
|
986
|
-
|
|
1060
|
+
native_flow_name:
|
|
1061
|
+
firstButtonName === "review_and_pay" ? "order_details" : firstButtonName,
|
|
1062
|
+
},
|
|
987
1063
|
};
|
|
988
|
-
}
|
|
989
|
-
if (message_flow && flow_buttons_special.includes(flow_buttons_first)) {
|
|
1064
|
+
} else if (nativeFlow && nativeFlowSpecials.includes(firstButtonName)) {
|
|
990
1065
|
return {
|
|
991
|
-
|
|
1066
|
+
tag: "biz",
|
|
1067
|
+
attrs: {
|
|
1068
|
+
actual_actors: "2",
|
|
1069
|
+
host_storage: "2",
|
|
1070
|
+
privacy_mode_ts: unixTimestampSeconds().toString(),
|
|
1071
|
+
},
|
|
992
1072
|
content: [
|
|
993
1073
|
{
|
|
994
|
-
tag:
|
|
995
|
-
attrs: { type:
|
|
996
|
-
content: [{
|
|
997
|
-
tag: 'native_flow',
|
|
998
|
-
attrs: { v: '2', name: flow_buttons_first }
|
|
999
|
-
}]
|
|
1074
|
+
tag: "interactive",
|
|
1075
|
+
attrs: { type: "native_flow", v: "1" },
|
|
1076
|
+
content: [{ tag: "native_flow", attrs: { v: "2", name: firstButtonName } }],
|
|
1000
1077
|
},
|
|
1001
|
-
{
|
|
1002
|
-
|
|
1003
|
-
attrs: { source_type: 'third_party' }
|
|
1004
|
-
}
|
|
1005
|
-
]
|
|
1078
|
+
{ tag: "quality_control", attrs: { source_type: "third_party" } },
|
|
1079
|
+
],
|
|
1006
1080
|
};
|
|
1007
|
-
}
|
|
1008
|
-
if (message_flow || message_content.buttonsMessage) {
|
|
1081
|
+
} else if (nativeFlow || message.buttonsMessage) {
|
|
1009
1082
|
return {
|
|
1010
|
-
|
|
1083
|
+
tag: "biz",
|
|
1084
|
+
attrs: {
|
|
1085
|
+
actual_actors: "2",
|
|
1086
|
+
host_storage: "2",
|
|
1087
|
+
privacy_mode_ts: unixTimestampSeconds().toString(),
|
|
1088
|
+
},
|
|
1011
1089
|
content: [
|
|
1012
1090
|
{
|
|
1013
|
-
tag:
|
|
1014
|
-
attrs: { type:
|
|
1015
|
-
content: [{
|
|
1016
|
-
tag: 'native_flow',
|
|
1017
|
-
attrs: { v: '9', name: 'mixed' }
|
|
1018
|
-
}]
|
|
1091
|
+
tag: "interactive",
|
|
1092
|
+
attrs: { type: "native_flow", v: "1" },
|
|
1093
|
+
content: [{ tag: "native_flow", attrs: { v: "9", name: "mixed" } }],
|
|
1019
1094
|
},
|
|
1020
|
-
{
|
|
1021
|
-
|
|
1022
|
-
attrs: { source_type: 'third_party' }
|
|
1023
|
-
}
|
|
1024
|
-
]
|
|
1095
|
+
{ tag: "quality_control", attrs: { source_type: "third_party" } },
|
|
1096
|
+
],
|
|
1025
1097
|
};
|
|
1026
|
-
}
|
|
1027
|
-
if (message_content.listMessage) {
|
|
1098
|
+
} else if (message.listMessage) {
|
|
1028
1099
|
return {
|
|
1029
|
-
|
|
1100
|
+
tag: "biz",
|
|
1101
|
+
attrs: {
|
|
1102
|
+
actual_actors: "2",
|
|
1103
|
+
host_storage: "2",
|
|
1104
|
+
privacy_mode_ts: unixTimestampSeconds().toString(),
|
|
1105
|
+
},
|
|
1030
1106
|
content: [
|
|
1031
|
-
{
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1107
|
+
{ tag: "list", attrs: { v: "2", type: "product_list" } },
|
|
1108
|
+
{ tag: "quality_control", attrs: { source_type: "third_party" } },
|
|
1109
|
+
],
|
|
1110
|
+
};
|
|
1111
|
+
} else {
|
|
1112
|
+
return {
|
|
1113
|
+
tag: "biz",
|
|
1114
|
+
attrs: {
|
|
1115
|
+
actual_actors: "2",
|
|
1116
|
+
host_storage: "2",
|
|
1117
|
+
privacy_mode_ts: unixTimestampSeconds().toString(),
|
|
1118
|
+
},
|
|
1040
1119
|
};
|
|
1041
1120
|
}
|
|
1042
|
-
return baseArgs;
|
|
1043
1121
|
};
|
|
1044
|
-
|
|
1045
1122
|
const getPrivacyTokens = async (jids) => {
|
|
1046
|
-
const t =
|
|
1047
|
-
|
|
1123
|
+
const t = unixTimestampSeconds().toString();
|
|
1048
1124
|
const result = await query({
|
|
1049
|
-
tag:
|
|
1050
|
-
attrs: {
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
return result
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1125
|
+
tag: "iq",
|
|
1126
|
+
attrs: { to: S_WHATSAPP_NET, type: "set", xmlns: "privacy" },
|
|
1127
|
+
content: [
|
|
1128
|
+
{
|
|
1129
|
+
tag: "tokens",
|
|
1130
|
+
attrs: {},
|
|
1131
|
+
content: jids.map((jid) => ({
|
|
1132
|
+
tag: "token",
|
|
1133
|
+
attrs: {
|
|
1134
|
+
jid: jidNormalizedUser(jid),
|
|
1135
|
+
t: t,
|
|
1136
|
+
type: "trusted_contact",
|
|
1137
|
+
},
|
|
1138
|
+
})),
|
|
1139
|
+
},
|
|
1140
|
+
],
|
|
1141
|
+
});
|
|
1142
|
+
return result;
|
|
1143
|
+
};
|
|
1072
1144
|
const getEphemeralGroup = (jid) => {
|
|
1073
|
-
if (!
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
}])
|
|
1081
|
-
.then((groups) => WABinary_1.getBinaryNodeChild(groups, 'group'))
|
|
1082
|
-
.then((metadata) => WABinary_1.getBinaryNodeChild(metadata, 'ephemeral')?.attrs?.expiration || 0)
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
const waUploadToServer = Utils_1.getWAUploadToServer(config, refreshMediaConn)
|
|
1086
|
-
|
|
1087
|
-
const waitForMsgMediaUpdate = Utils_1.bindWaitForEvent(ev, 'messages.media-update')
|
|
1088
|
-
|
|
1145
|
+
if (!isJidGroup(jid)) throw new TypeError("Jid should originate from a group!");
|
|
1146
|
+
return groupQuery(jid, "get", [{ tag: "query", attrs: { request: "interactive" } }])
|
|
1147
|
+
.then((groups) => getBinaryNodeChild(groups, "group"))
|
|
1148
|
+
.then((metadata) => getBinaryNodeChild(metadata, "ephemeral")?.attrs?.expiration || 0);
|
|
1149
|
+
};
|
|
1150
|
+
const waUploadToServer = getWAUploadToServer(config, refreshMediaConn);
|
|
1151
|
+
const waitForMsgMediaUpdate = bindWaitForEvent(ev, "messages.media-update");
|
|
1089
1152
|
return {
|
|
1090
|
-
...
|
|
1091
|
-
getPrivacyTokens,
|
|
1092
|
-
assertSessions,
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
getUSyncDevices,
|
|
1099
|
-
refreshMediaConn,
|
|
1100
|
-
waUploadToServer,
|
|
1101
|
-
getEphemeralGroup,
|
|
1102
|
-
fetchPrivacySettings,
|
|
1103
|
-
messageRetryManager,
|
|
1104
|
-
createParticipantNodes,
|
|
1105
|
-
sendPeerDataOperationMessage,
|
|
1153
|
+
...conn,
|
|
1154
|
+
getPrivacyTokens: getPrivacyTokens,
|
|
1155
|
+
assertSessions: assertSessions,
|
|
1156
|
+
profilePictureUrl: profilePictureUrl,
|
|
1157
|
+
relayMessage: relayMessage,
|
|
1158
|
+
sendReceipt: sendReceipt,
|
|
1159
|
+
sendReceipts: sendReceipts,
|
|
1160
|
+
readMessages: readMessages,
|
|
1161
|
+
getUSyncDevices: getUSyncDevices,
|
|
1162
|
+
refreshMediaConn: refreshMediaConn,
|
|
1163
|
+
waUploadToServer: waUploadToServer,
|
|
1164
|
+
getEphemeralGroup: getEphemeralGroup,
|
|
1165
|
+
fetchPrivacySettings: fetchPrivacySettings,
|
|
1166
|
+
messageRetryManager: messageRetryManager,
|
|
1167
|
+
createParticipantNodes: createParticipantNodes,
|
|
1168
|
+
sendPeerDataOperationMessage: sendPeerDataOperationMessage,
|
|
1169
|
+
updateMemberLabel: updateMemberLabel,
|
|
1106
1170
|
updateMediaMessage: async (message) => {
|
|
1107
|
-
const content =
|
|
1108
|
-
const mediaKey = content.mediaKey
|
|
1109
|
-
const meId = authState.creds.me.id
|
|
1110
|
-
const node = await
|
|
1111
|
-
let error = undefined
|
|
1112
|
-
|
|
1171
|
+
const content = assertMediaContent(message.message);
|
|
1172
|
+
const mediaKey = content.mediaKey;
|
|
1173
|
+
const meId = authState.creds.me.id;
|
|
1174
|
+
const node = await encryptMediaRetryRequest(message.key, mediaKey, meId);
|
|
1175
|
+
let error = undefined;
|
|
1113
1176
|
await Promise.all([
|
|
1114
1177
|
sendNode(node),
|
|
1115
1178
|
waitForMsgMediaUpdate(async (update) => {
|
|
1116
|
-
const result = update.find(c => c.key.id === message.key.id)
|
|
1179
|
+
const result = update.find((c) => c.key.id === message.key.id);
|
|
1117
1180
|
if (result) {
|
|
1118
1181
|
if (result.error) {
|
|
1119
|
-
error = result.error
|
|
1182
|
+
error = result.error;
|
|
1120
1183
|
} else {
|
|
1121
1184
|
try {
|
|
1122
|
-
const media = await
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1185
|
+
const media = await decryptMediaRetryData(
|
|
1186
|
+
result.media,
|
|
1187
|
+
mediaKey,
|
|
1188
|
+
result.key.id
|
|
1189
|
+
);
|
|
1190
|
+
if (
|
|
1191
|
+
media.result !== proto.MediaRetryNotification.ResultType.SUCCESS
|
|
1192
|
+
) {
|
|
1193
|
+
const resultStr =
|
|
1194
|
+
proto.MediaRetryNotification.ResultType[media.result];
|
|
1195
|
+
throw new Boom(
|
|
1196
|
+
`Media re-upload failed by device (${resultStr})`,
|
|
1197
|
+
{
|
|
1198
|
+
data: media,
|
|
1199
|
+
statusCode:
|
|
1200
|
+
getStatusCodeForMediaRetry(media.result) || 404,
|
|
1201
|
+
}
|
|
1202
|
+
);
|
|
1131
1203
|
}
|
|
1132
|
-
|
|
1133
|
-
content.
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
directPath: media.directPath,
|
|
1139
|
-
key: result.key
|
|
1140
|
-
}, 'media update successful')
|
|
1204
|
+
content.directPath = media.directPath;
|
|
1205
|
+
content.url = getUrlFromDirectPath(content.directPath);
|
|
1206
|
+
logger.debug(
|
|
1207
|
+
{ directPath: media.directPath, key: result.key },
|
|
1208
|
+
"media update successful"
|
|
1209
|
+
);
|
|
1141
1210
|
} catch (err) {
|
|
1142
|
-
error = err
|
|
1211
|
+
error = err;
|
|
1143
1212
|
}
|
|
1144
1213
|
}
|
|
1145
|
-
|
|
1146
|
-
return true
|
|
1214
|
+
return true;
|
|
1147
1215
|
}
|
|
1148
|
-
})
|
|
1149
|
-
])
|
|
1150
|
-
|
|
1216
|
+
}),
|
|
1217
|
+
]);
|
|
1151
1218
|
if (error) {
|
|
1152
|
-
throw error
|
|
1219
|
+
throw error;
|
|
1153
1220
|
}
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
message: message.message
|
|
1159
|
-
}
|
|
1160
|
-
}])
|
|
1161
|
-
|
|
1162
|
-
return message
|
|
1221
|
+
ev.emit("messages.update", [
|
|
1222
|
+
{ key: message.key, update: { message: message.message } },
|
|
1223
|
+
]);
|
|
1224
|
+
return message;
|
|
1163
1225
|
},
|
|
1164
1226
|
sendStatusMentions: async (content, jids = []) => {
|
|
1165
|
-
const
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
{ requested: jids.length, max: MAX_STATUS_MENTIONS },
|
|
1169
|
-
`sendStatusMentions: max ${MAX_STATUS_MENTIONS} mentions per status, truncating`
|
|
1170
|
-
)
|
|
1171
|
-
jids = jids.slice(0, MAX_STATUS_MENTIONS)
|
|
1172
|
-
}
|
|
1173
|
-
const userJid = WABinary_1.jidNormalizedUser(authState.creds.me.id)
|
|
1174
|
-
let allUsers = new Set()
|
|
1175
|
-
allUsers.add(userJid)
|
|
1176
|
-
|
|
1227
|
+
const userJid = jidNormalizedUser(authState.creds.me.id);
|
|
1228
|
+
let allUsers = new Set();
|
|
1229
|
+
allUsers.add(userJid);
|
|
1177
1230
|
for (const id of jids) {
|
|
1178
|
-
const isGroup =
|
|
1179
|
-
const isPrivate =
|
|
1180
|
-
|
|
1231
|
+
const isGroup = isJidGroup(id);
|
|
1232
|
+
const isPrivate = isPnUser(id);
|
|
1181
1233
|
if (isGroup) {
|
|
1182
1234
|
try {
|
|
1183
|
-
const metadata =
|
|
1184
|
-
|
|
1185
|
-
participants
|
|
1235
|
+
const metadata =
|
|
1236
|
+
(await cachedGroupMetadata(id)) || (await groupMetadata(id));
|
|
1237
|
+
const participants = metadata.participants.map((p) =>
|
|
1238
|
+
jidNormalizedUser(p.id)
|
|
1239
|
+
);
|
|
1240
|
+
participants.forEach((jid) => allUsers.add(jid));
|
|
1186
1241
|
} catch (error) {
|
|
1187
|
-
logger.error(`Error getting metadata for group ${id}: ${error}`)
|
|
1242
|
+
logger.error(`Error getting metadata for group ${id}: ${error}`);
|
|
1188
1243
|
}
|
|
1189
1244
|
} else if (isPrivate) {
|
|
1190
|
-
allUsers.add(
|
|
1245
|
+
allUsers.add(jidNormalizedUser(id));
|
|
1191
1246
|
}
|
|
1192
1247
|
}
|
|
1193
|
-
|
|
1194
|
-
const
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
const
|
|
1201
|
-
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1248
|
+
const uniqueUsers = Array.from(allUsers);
|
|
1249
|
+
const getRandomHexColor = () =>
|
|
1250
|
+
"#" +
|
|
1251
|
+
Math.floor(Math.random() * 16777215)
|
|
1252
|
+
.toString(16)
|
|
1253
|
+
.padStart(6, "0");
|
|
1254
|
+
const isMedia = content.image || content.video || content.audio;
|
|
1255
|
+
const isAudio = !!content.audio;
|
|
1256
|
+
const messageContent = { ...content };
|
|
1204
1257
|
if (isMedia && !isAudio) {
|
|
1205
1258
|
if (messageContent.text) {
|
|
1206
|
-
messageContent.caption = messageContent.text
|
|
1207
|
-
|
|
1208
|
-
delete messageContent.text
|
|
1259
|
+
messageContent.caption = messageContent.text;
|
|
1260
|
+
delete messageContent.text;
|
|
1209
1261
|
}
|
|
1210
|
-
|
|
1211
|
-
delete messageContent.
|
|
1212
|
-
delete messageContent.
|
|
1213
|
-
delete messageContent.
|
|
1214
|
-
delete messageContent.textColor
|
|
1262
|
+
delete messageContent.ptt;
|
|
1263
|
+
delete messageContent.font;
|
|
1264
|
+
delete messageContent.backgroundColor;
|
|
1265
|
+
delete messageContent.textColor;
|
|
1215
1266
|
}
|
|
1216
|
-
|
|
1217
1267
|
if (isAudio) {
|
|
1218
|
-
delete messageContent.text
|
|
1219
|
-
delete messageContent.caption
|
|
1220
|
-
delete messageContent.font
|
|
1221
|
-
delete messageContent.textColor
|
|
1268
|
+
delete messageContent.text;
|
|
1269
|
+
delete messageContent.caption;
|
|
1270
|
+
delete messageContent.font;
|
|
1271
|
+
delete messageContent.textColor;
|
|
1222
1272
|
}
|
|
1223
|
-
|
|
1224
|
-
const
|
|
1225
|
-
const
|
|
1226
|
-
|
|
1227
|
-
const ptt = isAudio
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1273
|
+
const font = !isMedia ? content.font || Math.floor(Math.random() * 9) : undefined;
|
|
1274
|
+
const textColor = !isMedia ? content.textColor || getRandomHexColor() : undefined;
|
|
1275
|
+
const backgroundColor =
|
|
1276
|
+
!isMedia || isAudio ? content.backgroundColor || getRandomHexColor() : undefined;
|
|
1277
|
+
const ptt = isAudio
|
|
1278
|
+
? typeof content.ptt === "boolean"
|
|
1279
|
+
? content.ptt
|
|
1280
|
+
: true
|
|
1281
|
+
: undefined;
|
|
1282
|
+
let msg;
|
|
1283
|
+
let mediaHandle;
|
|
1231
1284
|
try {
|
|
1232
|
-
msg = await
|
|
1233
|
-
logger,
|
|
1234
|
-
userJid,
|
|
1235
|
-
getUrlInfo: text =>
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
timeout:
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1285
|
+
msg = await generateWAMessage(STORIES_JID, messageContent, {
|
|
1286
|
+
logger: logger,
|
|
1287
|
+
userJid: userJid,
|
|
1288
|
+
getUrlInfo: (text) =>
|
|
1289
|
+
getUrlInfo(text, {
|
|
1290
|
+
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
1291
|
+
fetchOpts: { timeout: 3e3, ...(httpRequestOptions || {}) },
|
|
1292
|
+
logger: logger,
|
|
1293
|
+
uploadImage: generateHighQualityLinkPreview
|
|
1294
|
+
? waUploadToServer
|
|
1295
|
+
: undefined,
|
|
1296
|
+
}),
|
|
1244
1297
|
upload: async (encFilePath, opts) => {
|
|
1245
|
-
const up = await waUploadToServer(encFilePath, {
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
mediaHandle = up.handle
|
|
1249
|
-
return up
|
|
1298
|
+
const up = await waUploadToServer(encFilePath, { ...opts });
|
|
1299
|
+
mediaHandle = up.handle;
|
|
1300
|
+
return up;
|
|
1250
1301
|
},
|
|
1251
1302
|
mediaCache: config.mediaCache,
|
|
1252
1303
|
options: config.options,
|
|
1253
|
-
font,
|
|
1254
|
-
textColor,
|
|
1255
|
-
backgroundColor,
|
|
1256
|
-
ptt
|
|
1257
|
-
})
|
|
1304
|
+
font: font,
|
|
1305
|
+
textColor: textColor,
|
|
1306
|
+
backgroundColor: backgroundColor,
|
|
1307
|
+
ptt: ptt,
|
|
1308
|
+
});
|
|
1258
1309
|
} catch (error) {
|
|
1259
|
-
logger.error(`Error generating message: ${error}`)
|
|
1260
|
-
throw error
|
|
1310
|
+
logger.error(`Error generating message: ${error}`);
|
|
1311
|
+
throw error;
|
|
1261
1312
|
}
|
|
1262
|
-
|
|
1263
|
-
await relayMessage(WABinary_1.STORIES_JID, msg.message, {
|
|
1313
|
+
await relayMessage(STORIES_JID, msg.message, {
|
|
1264
1314
|
messageId: msg.key.id,
|
|
1265
1315
|
statusJidList: uniqueUsers,
|
|
1266
|
-
additionalNodes: [
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
content: [{
|
|
1270
|
-
tag: 'mentioned_users',
|
|
1316
|
+
additionalNodes: [
|
|
1317
|
+
{
|
|
1318
|
+
tag: "meta",
|
|
1271
1319
|
attrs: {},
|
|
1272
|
-
content:
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1320
|
+
content: [
|
|
1321
|
+
{
|
|
1322
|
+
tag: "mentioned_users",
|
|
1323
|
+
attrs: {},
|
|
1324
|
+
content: jids.map((jid) => ({
|
|
1325
|
+
tag: "to",
|
|
1326
|
+
attrs: { jid: jidNormalizedUser(jid) },
|
|
1327
|
+
})),
|
|
1328
|
+
},
|
|
1329
|
+
],
|
|
1330
|
+
},
|
|
1331
|
+
],
|
|
1332
|
+
});
|
|
1282
1333
|
for (const id of jids) {
|
|
1283
1334
|
try {
|
|
1284
|
-
const normalizedId =
|
|
1285
|
-
const isPrivate =
|
|
1286
|
-
const type = isPrivate ?
|
|
1287
|
-
|
|
1335
|
+
const normalizedId = jidNormalizedUser(id);
|
|
1336
|
+
const isPrivate = isPnUser(normalizedId);
|
|
1337
|
+
const type = isPrivate ? "statusMentionMessage" : "groupStatusMentionMessage";
|
|
1288
1338
|
const protocolMessage = {
|
|
1289
1339
|
[type]: {
|
|
1290
|
-
message: {
|
|
1291
|
-
protocolMessage: {
|
|
1292
|
-
key: msg.key,
|
|
1293
|
-
type: 25
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1340
|
+
message: { protocolMessage: { key: msg.key, type: 25 } },
|
|
1296
1341
|
},
|
|
1297
|
-
messageContextInfo: {
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
|
-
const statusMsg = await Utils_1.generateWAMessageFromContent(normalizedId,
|
|
1303
|
-
protocolMessage, {}
|
|
1304
|
-
)
|
|
1305
|
-
|
|
1306
|
-
await relayMessage(
|
|
1342
|
+
messageContextInfo: { messageSecret: randomBytes(32) },
|
|
1343
|
+
};
|
|
1344
|
+
const statusMsg = await generateWAMessageFromContent(
|
|
1307
1345
|
normalizedId,
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1346
|
+
protocolMessage,
|
|
1347
|
+
{}
|
|
1348
|
+
);
|
|
1349
|
+
await relayMessage(normalizedId, statusMsg.message, {
|
|
1350
|
+
additionalNodes: [
|
|
1351
|
+
{
|
|
1352
|
+
tag: "meta",
|
|
1353
|
+
attrs: isPrivate
|
|
1354
|
+
? { is_status_mention: "true" }
|
|
1355
|
+
: { is_group_status_mention: "true" },
|
|
1356
|
+
},
|
|
1357
|
+
],
|
|
1358
|
+
});
|
|
1359
|
+
await delay(2e3);
|
|
1321
1360
|
} catch (error) {
|
|
1322
|
-
logger.error(`Error sending to ${id}: ${error}`)
|
|
1361
|
+
logger.error(`Error sending to ${id}: ${error}`);
|
|
1323
1362
|
}
|
|
1324
1363
|
}
|
|
1325
|
-
|
|
1326
|
-
return msg
|
|
1364
|
+
return msg;
|
|
1327
1365
|
},
|
|
1366
|
+
// --- tambahan dari 1.0.11: kirim album (banyak media digabung 1 pesan) ---
|
|
1328
1367
|
sendAlbumMessage: async (jid, medias, options = {}) => {
|
|
1329
|
-
const userJid = authState.creds.me.id
|
|
1368
|
+
const userJid = authState.creds.me.id;
|
|
1330
1369
|
for (const media of medias) {
|
|
1331
|
-
if (!media.image && !media.video) throw new TypeError(`medias[i] must have image or video property`)
|
|
1370
|
+
if (!media.image && !media.video) throw new TypeError(`medias[i] must have image or video property`);
|
|
1332
1371
|
}
|
|
1333
|
-
if (medias.length < 2) throw new RangeError("Minimum 2 media")
|
|
1334
|
-
const time = options.delay || 500
|
|
1335
|
-
delete options.delay
|
|
1336
|
-
const album = await
|
|
1372
|
+
if (medias.length < 2) throw new RangeError("Minimum 2 media");
|
|
1373
|
+
const time = options.delay || 500;
|
|
1374
|
+
delete options.delay;
|
|
1375
|
+
const album = await generateWAMessageFromContent(jid, {
|
|
1337
1376
|
albumMessage: {
|
|
1338
1377
|
expectedImageCount: medias.filter(media => media.image).length,
|
|
1339
1378
|
expectedVideoCount: medias.filter(media => media.video).length,
|
|
@@ -1342,16 +1381,15 @@ const makeMessagesSocket = (config) => {
|
|
|
1342
1381
|
}, {
|
|
1343
1382
|
userJid,
|
|
1344
1383
|
...options
|
|
1345
|
-
})
|
|
1384
|
+
});
|
|
1346
1385
|
await relayMessage(jid, album.message, {
|
|
1347
1386
|
messageId: album.key.id
|
|
1348
|
-
})
|
|
1349
|
-
let
|
|
1350
|
-
let msg
|
|
1387
|
+
});
|
|
1388
|
+
let msg;
|
|
1351
1389
|
for (const i in medias) {
|
|
1352
|
-
const media = medias[i]
|
|
1390
|
+
const media = medias[i];
|
|
1353
1391
|
if (media.image) {
|
|
1354
|
-
msg = await
|
|
1392
|
+
msg = await generateWAMessage(jid, {
|
|
1355
1393
|
image: media.image,
|
|
1356
1394
|
...media,
|
|
1357
1395
|
...options
|
|
@@ -1360,15 +1398,14 @@ const makeMessagesSocket = (config) => {
|
|
|
1360
1398
|
upload: async (readStream, opts) => {
|
|
1361
1399
|
const up = await waUploadToServer(readStream, {
|
|
1362
1400
|
...opts,
|
|
1363
|
-
newsletter:
|
|
1364
|
-
})
|
|
1365
|
-
|
|
1366
|
-
return up
|
|
1401
|
+
newsletter: isJidNewsletter(jid)
|
|
1402
|
+
});
|
|
1403
|
+
return up;
|
|
1367
1404
|
},
|
|
1368
1405
|
...options
|
|
1369
|
-
})
|
|
1406
|
+
});
|
|
1370
1407
|
} else if (media.video) {
|
|
1371
|
-
msg = await
|
|
1408
|
+
msg = await generateWAMessage(jid, {
|
|
1372
1409
|
video: media.video,
|
|
1373
1410
|
...media,
|
|
1374
1411
|
...options
|
|
@@ -1377,138 +1414,145 @@ const makeMessagesSocket = (config) => {
|
|
|
1377
1414
|
upload: async (readStream, opts) => {
|
|
1378
1415
|
const up = await waUploadToServer(readStream, {
|
|
1379
1416
|
...opts,
|
|
1380
|
-
newsletter:
|
|
1381
|
-
})
|
|
1382
|
-
|
|
1383
|
-
return up
|
|
1417
|
+
newsletter: isJidNewsletter(jid)
|
|
1418
|
+
});
|
|
1419
|
+
return up;
|
|
1384
1420
|
},
|
|
1385
1421
|
...options,
|
|
1386
|
-
})
|
|
1422
|
+
});
|
|
1387
1423
|
}
|
|
1388
1424
|
if (msg) {
|
|
1389
1425
|
msg.message.messageContextInfo = {
|
|
1390
|
-
messageSecret:
|
|
1426
|
+
messageSecret: randomBytes(32),
|
|
1391
1427
|
messageAssociation: {
|
|
1392
1428
|
associationType: 1,
|
|
1393
1429
|
parentMessageKey: album.key
|
|
1394
1430
|
}
|
|
1395
|
-
}
|
|
1431
|
+
};
|
|
1396
1432
|
}
|
|
1397
1433
|
await relayMessage(jid, msg.message, {
|
|
1398
1434
|
messageId: msg.key.id
|
|
1399
|
-
})
|
|
1400
|
-
await
|
|
1435
|
+
});
|
|
1436
|
+
await delay(time);
|
|
1401
1437
|
}
|
|
1402
|
-
return album
|
|
1438
|
+
return album;
|
|
1403
1439
|
},
|
|
1440
|
+
// --- akhir tambahan ---
|
|
1404
1441
|
sendMessage: async (jid, content, options = {}) => {
|
|
1405
|
-
const userJid = authState.creds.me.id
|
|
1406
|
-
const additionalAttributes = {}
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
}
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1442
|
+
const userJid = authState.creds.me.id;
|
|
1443
|
+
const additionalAttributes = {};
|
|
1444
|
+
if (!options.ephemeralExpiration) {
|
|
1445
|
+
if (isJidGroup(jid)) {
|
|
1446
|
+
const expiration = await getEphemeralGroup(jid);
|
|
1447
|
+
options.ephemeralExpiration = expiration;
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
if (
|
|
1451
|
+
typeof content === "object" &&
|
|
1452
|
+
"disappearingMessagesInChat" in content &&
|
|
1453
|
+
typeof content["disappearingMessagesInChat"] !== "undefined" &&
|
|
1454
|
+
isJidGroup(jid)
|
|
1455
|
+
) {
|
|
1456
|
+
const { disappearingMessagesInChat: disappearingMessagesInChat } = content;
|
|
1457
|
+
const value =
|
|
1458
|
+
typeof disappearingMessagesInChat === "boolean"
|
|
1459
|
+
? disappearingMessagesInChat
|
|
1460
|
+
? WA_DEFAULT_EPHEMERAL
|
|
1461
|
+
: 0
|
|
1462
|
+
: disappearingMessagesInChat;
|
|
1463
|
+
await groupToggleEphemeral(jid, value);
|
|
1464
|
+
} else if (typeof content === "object" && "album" in content && content.album) {
|
|
1465
|
+
const albumMsg = await prepareAlbumMessageContent(jid, content.album, {
|
|
1466
|
+
conn: {
|
|
1467
|
+
relayMessage: relayMessage,
|
|
1468
|
+
waUploadToServer: waUploadToServer,
|
|
1417
1469
|
},
|
|
1418
1470
|
userJid: userJid,
|
|
1419
|
-
...options
|
|
1420
|
-
})
|
|
1421
|
-
|
|
1471
|
+
...options,
|
|
1472
|
+
});
|
|
1422
1473
|
for (const media of albumMsg) {
|
|
1423
|
-
await
|
|
1474
|
+
await delay(options.delay || 500);
|
|
1424
1475
|
await relayMessage(jid, media.message, {
|
|
1425
1476
|
messageId: media.key.id,
|
|
1426
1477
|
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1427
|
-
additionalAttributes,
|
|
1478
|
+
additionalAttributes: additionalAttributes,
|
|
1428
1479
|
statusJidList: options.statusJidList,
|
|
1429
1480
|
additionalNodes: options.additionalNodes,
|
|
1430
|
-
|
|
1431
|
-
})
|
|
1481
|
+
AI: options.ai,
|
|
1482
|
+
});
|
|
1432
1483
|
}
|
|
1433
|
-
|
|
1434
|
-
return albumMsg
|
|
1484
|
+
return albumMsg;
|
|
1435
1485
|
} else {
|
|
1436
|
-
let mediaHandle
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
}),
|
|
1486
|
+
let mediaHandle;
|
|
1487
|
+
const fullMsg = await generateWAMessage(jid, content, {
|
|
1488
|
+
logger: logger,
|
|
1489
|
+
userJid: userJid,
|
|
1490
|
+
getUrlInfo: (text) =>
|
|
1491
|
+
getUrlInfo(text, {
|
|
1492
|
+
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
1493
|
+
fetchOpts: { timeout: 3e3, ...(httpRequestOptions || {}) },
|
|
1494
|
+
logger: logger,
|
|
1495
|
+
uploadImage: generateHighQualityLinkPreview
|
|
1496
|
+
? waUploadToServer
|
|
1497
|
+
: undefined,
|
|
1498
|
+
}),
|
|
1450
1499
|
getProfilePicUrl: profilePictureUrl,
|
|
1451
1500
|
getCallLink: createCallLink,
|
|
1452
1501
|
upload: async (encFilePath, opts) => {
|
|
1453
1502
|
const up = await waUploadToServer(encFilePath, {
|
|
1454
1503
|
...opts,
|
|
1455
|
-
newsletter:
|
|
1456
|
-
})
|
|
1457
|
-
mediaHandle = up.handle
|
|
1458
|
-
return up
|
|
1504
|
+
newsletter: isJidNewsletter(jid),
|
|
1505
|
+
});
|
|
1506
|
+
mediaHandle = up.handle;
|
|
1507
|
+
return up;
|
|
1459
1508
|
},
|
|
1460
1509
|
mediaCache: config.mediaCache,
|
|
1461
1510
|
options: config.options,
|
|
1462
|
-
messageId:
|
|
1511
|
+
messageId: generateMessageID(userJid),
|
|
1463
1512
|
...options,
|
|
1464
|
-
})
|
|
1465
|
-
|
|
1466
|
-
const
|
|
1467
|
-
const
|
|
1468
|
-
const
|
|
1469
|
-
const isKeep = 'keep' in content && !!content.keep && content.keep?.type === 2
|
|
1470
|
-
|
|
1513
|
+
});
|
|
1514
|
+
const isPin = "pin" in content && !!content.pin;
|
|
1515
|
+
const isEdit = "edit" in content && !!content.edit;
|
|
1516
|
+
const isDelete = "delete" in content && !!content.delete;
|
|
1517
|
+
const isKeep = "keep" in content && !!content.keep && content.keep?.type === 2;
|
|
1471
1518
|
if (isDelete || isKeep) {
|
|
1472
|
-
if (
|
|
1473
|
-
|
|
1519
|
+
if (
|
|
1520
|
+
(isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) ||
|
|
1521
|
+
isJidNewsletter(jid)
|
|
1522
|
+
) {
|
|
1523
|
+
additionalAttributes.edit = "8";
|
|
1474
1524
|
} else {
|
|
1475
|
-
additionalAttributes.edit =
|
|
1525
|
+
additionalAttributes.edit = "7";
|
|
1476
1526
|
}
|
|
1477
1527
|
} else if (isEdit) {
|
|
1478
|
-
additionalAttributes.edit =
|
|
1528
|
+
additionalAttributes.edit = isJidNewsletter(jid) ? "3" : "1";
|
|
1479
1529
|
} else if (isPin) {
|
|
1480
|
-
additionalAttributes.edit =
|
|
1530
|
+
additionalAttributes.edit = "2";
|
|
1481
1531
|
}
|
|
1482
|
-
|
|
1483
1532
|
if (mediaHandle) {
|
|
1484
|
-
additionalAttributes[
|
|
1533
|
+
additionalAttributes["media_id"] = mediaHandle;
|
|
1485
1534
|
}
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1535
|
+
if ("cachedGroupMetadata" in options) {
|
|
1536
|
+
console.warn(
|
|
1537
|
+
"cachedGroupMetadata in sendMessage are deprecated, now cachedGroupMetadata is part of the socket config."
|
|
1538
|
+
);
|
|
1489
1539
|
}
|
|
1490
|
-
|
|
1491
1540
|
await relayMessage(jid, fullMsg.message, {
|
|
1492
1541
|
messageId: fullMsg.key.id,
|
|
1493
1542
|
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1494
|
-
additionalAttributes,
|
|
1543
|
+
additionalAttributes: additionalAttributes,
|
|
1495
1544
|
statusJidList: options.statusJidList,
|
|
1496
1545
|
additionalNodes: options.additionalNodes,
|
|
1497
|
-
|
|
1498
|
-
})
|
|
1499
|
-
|
|
1546
|
+
AI: options.ai,
|
|
1547
|
+
});
|
|
1500
1548
|
if (config.emitOwnEvents) {
|
|
1501
|
-
process.nextTick(() => {
|
|
1502
|
-
|
|
1503
|
-
})
|
|
1549
|
+
process.nextTick(async () => {
|
|
1550
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, "append"));
|
|
1551
|
+
});
|
|
1504
1552
|
}
|
|
1505
|
-
|
|
1506
|
-
return fullMsg
|
|
1553
|
+
return fullMsg;
|
|
1507
1554
|
}
|
|
1508
|
-
}
|
|
1509
|
-
}
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
|
-
module.exports = {
|
|
1513
|
-
makeMessagesSocket
|
|
1514
|
-
}
|
|
1555
|
+
},
|
|
1556
|
+
};
|
|
1557
|
+
};
|
|
1558
|
+
module.exports = { makeMessagesSocket: makeMessagesSocket };
|