sauruspro-bail 0.0.0-stage → 5.0.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 +129 -2
- package/WAProto/GenerateStatics.sh +3 -0
- package/WAProto/WAProto.proto +6754 -0
- package/WAProto/fix-imports.js +85 -0
- package/WAProto/index.d.ts +79257 -0
- package/WAProto/index.js +242946 -0
- package/docs/CHANGELOG.md +22 -0
- package/docs/NEWSLETTER-STATUS.md +120 -0
- package/docs/SPR.md +51 -0
- package/engine-requirements.js +10 -0
- package/lib/Defaults/index.js +131 -0
- package/lib/Signal/Group/ciphertext-message.js +12 -0
- package/lib/Signal/Group/group-session-builder.js +30 -0
- package/lib/Signal/Group/group_cipher.js +82 -0
- package/lib/Signal/Group/index.js +12 -0
- package/lib/Signal/Group/keyhelper.js +18 -0
- package/lib/Signal/Group/sender-chain-key.js +26 -0
- package/lib/Signal/Group/sender-key-distribution-message.js +63 -0
- package/lib/Signal/Group/sender-key-message.js +66 -0
- package/lib/Signal/Group/sender-key-name.js +48 -0
- package/lib/Signal/Group/sender-key-record.js +41 -0
- package/lib/Signal/Group/sender-key-state.js +84 -0
- package/lib/Signal/Group/sender-message-key.js +26 -0
- package/lib/Signal/libsignal.js +431 -0
- package/lib/Signal/lid-mapping.js +277 -0
- package/lib/Socket/Client/index.js +3 -0
- package/lib/Socket/Client/types.js +11 -0
- package/lib/Socket/Client/websocket.js +54 -0
- package/lib/Socket/MessageBuilder.js +3729 -0
- package/lib/Socket/business.js +379 -0
- package/lib/Socket/chats.js +1198 -0
- package/lib/Socket/communities.js +431 -0
- package/lib/Socket/graphql.js +716 -0
- package/lib/Socket/groups.js +374 -0
- package/lib/Socket/index.js +92 -0
- package/lib/Socket/interop.js +463 -0
- package/lib/Socket/luxu.js +387 -0
- package/lib/Socket/message-builder.js +556 -0
- package/lib/Socket/messages-recv.js +1916 -0
- package/lib/Socket/messages-send.js +1516 -0
- package/lib/Socket/mex.js +54 -0
- package/lib/Socket/newsletter.js +641 -0
- package/lib/Socket/privacy.js +318 -0
- package/lib/Socket/socket.js +1115 -0
- package/lib/Socket/username.js +236 -0
- package/lib/Store/index.js +10 -0
- package/lib/Store/keyed-db.js +108 -0
- package/lib/Store/make-cache-manager-store.js +85 -0
- package/lib/Store/make-in-memory-store.js +244 -0
- package/lib/Store/make-ordered-dictionary.js +75 -0
- package/lib/Store/object-repository.js +32 -0
- package/lib/Types/Auth.js +2 -0
- package/lib/Types/Bussines.js +2 -0
- package/lib/Types/Call.js +2 -0
- package/lib/Types/Chat.js +8 -0
- package/lib/Types/Contact.js +2 -0
- package/lib/Types/Events.js +2 -0
- package/lib/Types/GroupMetadata.js +2 -0
- package/lib/Types/Label.js +25 -0
- package/lib/Types/LabelAssociation.js +7 -0
- package/lib/Types/Message.js +11 -0
- package/lib/Types/Mex.js +111 -0
- package/lib/Types/Product.js +2 -0
- package/lib/Types/Signal.js +2 -0
- package/lib/Types/Socket.js +3 -0
- package/lib/Types/State.js +56 -0
- package/lib/Types/USync.js +2 -0
- package/lib/Types/index.js +26 -0
- package/lib/Utils/auth-utils.js +302 -0
- package/lib/Utils/browser-utils.js +48 -0
- package/lib/Utils/business.js +231 -0
- package/lib/Utils/chat-utils.js +872 -0
- package/lib/Utils/companion-reg-client-utils.js +35 -0
- package/lib/Utils/crypto.js +118 -0
- package/lib/Utils/decode-wa-message.js +350 -0
- package/lib/Utils/dinolith-spr.d.ts +26 -0
- package/lib/Utils/dinolith-spr.js +521 -0
- package/lib/Utils/event-buffer.js +622 -0
- package/lib/Utils/generics.js +403 -0
- package/lib/Utils/history.js +134 -0
- package/lib/Utils/identity-change-handler.js +50 -0
- package/lib/Utils/index.js +26 -0
- package/lib/Utils/link-preview.js +85 -0
- package/lib/Utils/logger.js +3 -0
- package/lib/Utils/lt-hash.js +8 -0
- package/lib/Utils/make-mutex.js +33 -0
- package/lib/Utils/message-composer.js +273 -0
- package/lib/Utils/message-retry-manager.js +265 -0
- package/lib/Utils/messages-media.js +870 -0
- package/lib/Utils/messages.js +1394 -0
- package/lib/Utils/newsletter-status.d.ts +163 -0
- package/lib/Utils/newsletter-status.js +738 -0
- package/lib/Utils/noise-handler.js +201 -0
- package/lib/Utils/offline-node-processor.js +40 -0
- package/lib/Utils/pre-key-manager.js +106 -0
- package/lib/Utils/process-message.js +630 -0
- package/lib/Utils/reporting-utils.js +258 -0
- package/lib/Utils/signal.js +201 -0
- package/lib/Utils/stanza-ack.js +38 -0
- package/lib/Utils/sticker.js +133 -0
- package/lib/Utils/sync-action-utils.js +49 -0
- package/lib/Utils/tc-token-utils.js +163 -0
- package/lib/Utils/use-multi-file-auth-state.js +121 -0
- package/lib/Utils/use-sqlite-auth-state.js +162 -0
- package/lib/Utils/validate-connection.js +203 -0
- package/lib/WABinary/constants.js +1301 -0
- package/lib/WABinary/decode.js +262 -0
- package/lib/WABinary/encode.js +220 -0
- package/lib/WABinary/generic-utils.js +204 -0
- package/lib/WABinary/index.js +6 -0
- package/lib/WABinary/jid-utils.js +98 -0
- package/lib/WABinary/types.js +2 -0
- package/lib/WAM/BinaryInfo.js +10 -0
- package/lib/WAM/constants.js +22853 -0
- package/lib/WAM/encode.js +150 -0
- package/lib/WAM/index.js +4 -0
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +53 -0
- package/lib/WAUSync/Protocols/USyncBusinessProtocol.js +43 -0
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +54 -0
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +57 -0
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +30 -0
- package/lib/WAUSync/Protocols/USyncFeatureProtocol.js +58 -0
- package/lib/WAUSync/Protocols/USyncLIDProtocol.js +30 -0
- package/lib/WAUSync/Protocols/USyncPictureProtocol.js +32 -0
- package/lib/WAUSync/Protocols/USyncSidelistProtocol.js +28 -0
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +39 -0
- package/lib/WAUSync/Protocols/USyncTextStatusProtocol.js +38 -0
- package/lib/WAUSync/Protocols/USyncUsernameProtocol.js +27 -0
- package/lib/WAUSync/Protocols/index.js +12 -0
- package/lib/WAUSync/USyncQuery.js +151 -0
- package/lib/WAUSync/USyncUser.js +56 -0
- package/lib/WAUSync/index.js +3 -0
- package/lib/index.js +67 -0
- package/package.json +147 -5
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Do not remove this watermark.
|
|
3
|
+
*
|
|
4
|
+
* NIXCODE - Advanced WhatsApp Send Private Relay
|
|
5
|
+
*
|
|
6
|
+
* Runtime:
|
|
7
|
+
* - sauruspro-bail (ESM port of the diezyxhao-baileys SPR, logic unchanged)
|
|
8
|
+
*
|
|
9
|
+
* Created by Nixel
|
|
10
|
+
* WhatsApp: wa.me/6285188349341
|
|
11
|
+
* Channel: https://whatsapp.com/channel/0029VbCV1ck8fewpdNb2TY2k
|
|
12
|
+
*
|
|
13
|
+
* Copyright (c) 2026 Nixel
|
|
14
|
+
*
|
|
15
|
+
* Permission is granted to use and modify this library
|
|
16
|
+
* for personal or commercial projects.
|
|
17
|
+
*
|
|
18
|
+
* Reuploading, reselling, relicensing, or redistributing
|
|
19
|
+
* this library as a standalone product is prohibited.
|
|
20
|
+
*
|
|
21
|
+
* Do not claim this project as your own original work.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
"use strict";
|
|
25
|
+
|
|
26
|
+
import { proto } from '../../WAProto/index.js';
|
|
27
|
+
import { Curve } from './crypto.js';
|
|
28
|
+
import { generateMessageIDV2, generateParticipantHashV2, encodeWAMessage, encodeNewsletterMessage } from './generics.js';
|
|
29
|
+
import { encodeSignedDeviceIdentity } from './validate-connection.js';
|
|
30
|
+
import { normalizeMessageContent } from './messages.js';
|
|
31
|
+
import { isHostedLidUser, isHostedPnUser, isLidUser, jidDecode, jidEncode } from '../WABinary/index.js';
|
|
32
|
+
import { Boom } from '@hapi/boom';
|
|
33
|
+
import crypto from 'crypto';
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
function encodeVarint(value) {
|
|
38
|
+
const bytes = [];
|
|
39
|
+
while (value >= 128) {
|
|
40
|
+
bytes.push((value & 127) | 128);
|
|
41
|
+
value >>>= 7;
|
|
42
|
+
}
|
|
43
|
+
bytes.push(value);
|
|
44
|
+
return Buffer.from(bytes);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function generateSigningKeyPair() {
|
|
48
|
+
const keys = Curve.generateKeyPair();
|
|
49
|
+
const pubBuffer = Buffer.concat([Buffer.from([0x05]), Buffer.from(keys.public)]);
|
|
50
|
+
return { privateKey: Buffer.from(keys.private), publicKey: pubBuffer };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function getMessageKey(seed) {
|
|
54
|
+
const messageKey = crypto.createHmac("sha256", seed).update(Buffer.from([0x01])).digest();
|
|
55
|
+
const salt = Buffer.alloc(32, 0);
|
|
56
|
+
const info = Buffer.from("WhisperGroup");
|
|
57
|
+
const prk = crypto.createHmac("sha256", salt).update(messageKey).digest();
|
|
58
|
+
const t1 = crypto.createHmac("sha256", prk).update(Buffer.concat([info, Buffer.from([0x01])])).digest();
|
|
59
|
+
const t2 = crypto.createHmac("sha256", prk).update(Buffer.concat([t1, info, Buffer.from([0x02])])).digest();
|
|
60
|
+
const okm = Buffer.concat([t1, t2]);
|
|
61
|
+
const iv = okm.slice(0, 16);
|
|
62
|
+
const cipherKey = okm.slice(16, 48);
|
|
63
|
+
return { iv, cipherKey };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function deriveReportingTag(message, msgId, remoteJid) {
|
|
67
|
+
if (!message.messageContextInfo) message.messageContextInfo = {};
|
|
68
|
+
if (!Buffer.isBuffer(message.messageContextInfo.messageSecret) || message.messageContextInfo.messageSecret.length !== 32) {
|
|
69
|
+
message.messageContextInfo.messageSecret = crypto.randomBytes(32);
|
|
70
|
+
}
|
|
71
|
+
const seed = message.messageContextInfo.messageSecret;
|
|
72
|
+
const payload = Buffer.from(proto.Message.encode(message).finish());
|
|
73
|
+
const salt = Buffer.alloc(32, 0);
|
|
74
|
+
const info = Buffer.concat([
|
|
75
|
+
Buffer.from(msgId, "utf8"),
|
|
76
|
+
Buffer.from(remoteJid, "utf8"),
|
|
77
|
+
Buffer.from(remoteJid, "utf8"),
|
|
78
|
+
Buffer.from("Report Token", "utf8")
|
|
79
|
+
]);
|
|
80
|
+
const prk = crypto.createHmac("sha256", salt).update(seed).digest();
|
|
81
|
+
const t1 = crypto.createHmac("sha256", prk).update(Buffer.concat([info, Buffer.from([0x01])])).digest();
|
|
82
|
+
const mac = crypto.createHmac("sha256", t1).update(payload).digest();
|
|
83
|
+
|
|
84
|
+
const iv = Buffer.from([0x7a, 0x3b, 0x91, 0xc4, 0x2e, 0x1f, 0xd0, 0x63]);
|
|
85
|
+
const vec = Buffer.from([0x29, 0x6b, 0xc3, 0x8a, 0x67, 0x47, 0x95, 0x2f, 0x2c, 0x0a]);
|
|
86
|
+
const nonce = mac.subarray(0, 4);
|
|
87
|
+
const stream = crypto.createHmac("sha256", iv).update(nonce).digest();
|
|
88
|
+
|
|
89
|
+
const raw = Buffer.alloc(10);
|
|
90
|
+
for (let i = 0; i < 10; i++) {
|
|
91
|
+
raw[i] = vec[i] ^ iv[i & 7];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const sig = crypto.createHmac("sha256", iv).update(Buffer.concat([nonce, raw])).digest().subarray(0, 2);
|
|
95
|
+
const block = Buffer.concat([raw, sig]);
|
|
96
|
+
|
|
97
|
+
for (let i = 0; i < 12; i++) {
|
|
98
|
+
block[i] ^= stream[i];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return Buffer.concat([nonce, block]);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function encryptGroupMessage(plaintext, chainSeed, privateKeyObject, keyId) {
|
|
105
|
+
const iteration = 0;
|
|
106
|
+
const { iv, cipherKey } = getMessageKey(chainSeed);
|
|
107
|
+
const cipher = crypto.createCipheriv("aes-256-cbc", cipherKey, iv);
|
|
108
|
+
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
109
|
+
const idBuf = Buffer.concat([Buffer.from([0x08]), encodeVarint(keyId)]);
|
|
110
|
+
const iterBuf = Buffer.concat([Buffer.from([0x10]), encodeVarint(iteration)]);
|
|
111
|
+
const cipherBuf = Buffer.concat([Buffer.from([0x1A]), encodeVarint(ciphertext.length), ciphertext]);
|
|
112
|
+
const messageProto = Buffer.concat([idBuf, iterBuf, cipherBuf]);
|
|
113
|
+
const messageToSign = Buffer.concat([Buffer.from([0x33]), messageProto]);
|
|
114
|
+
const signature = Curve.sign(privateKeyObject, messageToSign);
|
|
115
|
+
return Buffer.concat([messageToSign, Buffer.from(signature)]);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function createSKDM(keyId, iteration, chainSeed, signingPubKey) {
|
|
119
|
+
const idBuf = Buffer.concat([Buffer.from([0x08]), encodeVarint(keyId)]);
|
|
120
|
+
const iterBuf = Buffer.concat([Buffer.from([0x10]), encodeVarint(iteration)]);
|
|
121
|
+
const chainBuf = Buffer.concat([Buffer.from([0x1A]), encodeVarint(chainSeed.length), chainSeed]);
|
|
122
|
+
const signBuf = Buffer.concat([Buffer.from([0x22]), encodeVarint(signingPubKey.length), signingPubKey]);
|
|
123
|
+
const message = Buffer.concat([idBuf, iterBuf, chainBuf, signBuf]);
|
|
124
|
+
return Buffer.concat([Buffer.from([0x33]), message]);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const getMessageType = (message) => {
|
|
128
|
+
const normalizedMessage = normalizeMessageContent(message);
|
|
129
|
+
if (!normalizedMessage) return "text";
|
|
130
|
+
if (normalizedMessage.reactionMessage || normalizedMessage.encReactionMessage) return "reaction";
|
|
131
|
+
if (
|
|
132
|
+
normalizedMessage.pollCreationMessage ||
|
|
133
|
+
normalizedMessage.pollCreationMessageV2 ||
|
|
134
|
+
normalizedMessage.pollCreationMessageV3 ||
|
|
135
|
+
normalizedMessage.pollUpdateMessage
|
|
136
|
+
) return "poll";
|
|
137
|
+
if (normalizedMessage.eventMessage) return "event";
|
|
138
|
+
if (getMediaType(normalizedMessage) !== "") return "media";
|
|
139
|
+
return "text";
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const getMediaType = (message) => {
|
|
143
|
+
if (message.imageMessage) return "image";
|
|
144
|
+
if (message.videoMessage) return message.videoMessage.gifPlayback ? "gif" : "video";
|
|
145
|
+
if (message.audioMessage) return message.audioMessage.ptt ? "ptt" : "audio";
|
|
146
|
+
if (message.contactMessage) return "vcard";
|
|
147
|
+
if (message.documentMessage) return "document";
|
|
148
|
+
if (message.contactsArrayMessage) return "contact_array";
|
|
149
|
+
if (message.liveLocationMessage) return "livelocation";
|
|
150
|
+
if (message.stickerMessage) return "sticker";
|
|
151
|
+
if (message.listMessage) return "list";
|
|
152
|
+
if (message.listResponseMessage) return "list_response";
|
|
153
|
+
if (message.buttonsResponseMessage) return "buttons_response";
|
|
154
|
+
if (message.orderMessage) return "order";
|
|
155
|
+
if (message.productMessage) return "product";
|
|
156
|
+
if (message.interactiveResponseMessage) return "native_flow_response";
|
|
157
|
+
if (message.groupInviteMessage) return "url";
|
|
158
|
+
return "";
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export async function sPR(conn, jid, message, {
|
|
162
|
+
messageId: msgId,
|
|
163
|
+
additionalAttributes,
|
|
164
|
+
useUserDevicesCache,
|
|
165
|
+
useCachedGroupMetadata,
|
|
166
|
+
statusJidList,
|
|
167
|
+
additionalNodes,
|
|
168
|
+
targetMe,
|
|
169
|
+
mode = "exclude",
|
|
170
|
+
target = [],
|
|
171
|
+
hideDecryptFail = true,
|
|
172
|
+
deviceMode = "all"
|
|
173
|
+
} = {}) {
|
|
174
|
+
const meId = conn.authState?.creds?.me?.id || conn.user?.id || "";
|
|
175
|
+
const meLid = conn.authState?.creds?.me?.lid || conn.user?.lid || "";
|
|
176
|
+
|
|
177
|
+
const getLidForPn = async (pnJid) => {
|
|
178
|
+
try {
|
|
179
|
+
return await conn.signalRepository?.lidMapping?.getLIDForPN(pnJid);
|
|
180
|
+
} catch {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const getPnForLid = async (lidJid) => {
|
|
186
|
+
try {
|
|
187
|
+
return await conn.signalRepository?.lidMapping?.getPNForLID(lidJid);
|
|
188
|
+
} catch {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const processFilters = async (list) => {
|
|
194
|
+
const rules = [];
|
|
195
|
+
if (!Array.isArray(list)) return rules;
|
|
196
|
+
for (const item of list) {
|
|
197
|
+
if (!item) continue;
|
|
198
|
+
const decoded = jidDecode(item);
|
|
199
|
+
if (!decoded) continue;
|
|
200
|
+
|
|
201
|
+
const hasDevice = item.includes(":");
|
|
202
|
+
const targetDevice = hasDevice ? (decoded.device !== undefined ? decoded.device : 0) : null;
|
|
203
|
+
|
|
204
|
+
rules.push({
|
|
205
|
+
user: decoded.user,
|
|
206
|
+
device: targetDevice,
|
|
207
|
+
server: decoded.server
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
if (decoded.server === "s.whatsapp.net") {
|
|
211
|
+
const lidJid = await getLidForPn(item);
|
|
212
|
+
if (lidJid) {
|
|
213
|
+
const lidDecoded = jidDecode(lidJid);
|
|
214
|
+
if (lidDecoded) {
|
|
215
|
+
rules.push({
|
|
216
|
+
user: lidDecoded.user,
|
|
217
|
+
device: targetDevice,
|
|
218
|
+
server: lidDecoded.server
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
} else if (decoded.server === "lid") {
|
|
223
|
+
const pnJid = await getPnForLid(item);
|
|
224
|
+
if (pnJid) {
|
|
225
|
+
const pnDecoded = jidDecode(pnJid);
|
|
226
|
+
if (pnDecoded) {
|
|
227
|
+
rules.push({
|
|
228
|
+
user: pnDecoded.user,
|
|
229
|
+
device: targetDevice,
|
|
230
|
+
server: pnDecoded.server
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return rules;
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const parsedTargets = await processFilters(target);
|
|
240
|
+
|
|
241
|
+
const isMatch = (targetJid, rules) => {
|
|
242
|
+
const decoded = jidDecode(targetJid);
|
|
243
|
+
if (!decoded) return false;
|
|
244
|
+
|
|
245
|
+
const targetDevice = decoded.device !== undefined ? decoded.device : 0;
|
|
246
|
+
|
|
247
|
+
for (const rule of rules) {
|
|
248
|
+
if (rule.user === decoded.user) {
|
|
249
|
+
if (rule.device === null) return true;
|
|
250
|
+
if (rule.device === targetDevice) return true;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return false;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
let shouldIncludeDeviceIdentity = false;
|
|
257
|
+
const statusJid = "status@broadcast";
|
|
258
|
+
const { user, server } = jidDecode(jid);
|
|
259
|
+
const isNewsletter = server === "newsletter";
|
|
260
|
+
const isGroup = server === "g.us";
|
|
261
|
+
const isStatus = jid === statusJid;
|
|
262
|
+
const isGroupOrStatus = isGroup || isStatus;
|
|
263
|
+
msgId = msgId || generateMessageIDV2(meId);
|
|
264
|
+
useUserDevicesCache = useUserDevicesCache !== false;
|
|
265
|
+
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus;
|
|
266
|
+
const participants = [];
|
|
267
|
+
const destinationJid = !isStatus ? jid : statusJid;
|
|
268
|
+
const binaryNodeContent = [];
|
|
269
|
+
const devices = [];
|
|
270
|
+
|
|
271
|
+
const reportingToken = !isNewsletter && !isStatus ? deriveReportingTag(message, msgId, destinationJid) : null;
|
|
272
|
+
|
|
273
|
+
const meMsg = { deviceSentMessage: { destinationJid, message }, messageContextInfo: message.messageContextInfo };
|
|
274
|
+
const extraAttrs = {};
|
|
275
|
+
const messages = normalizeMessageContent(message);
|
|
276
|
+
|
|
277
|
+
if (isNewsletter) {
|
|
278
|
+
const patched = conn.patchMessageBeforeSending ? await conn.patchMessageBeforeSending(message, []) : message;
|
|
279
|
+
const bytes = encodeNewsletterMessage(patched);
|
|
280
|
+
binaryNodeContent.push({ tag: "plaintext", attrs: {}, content: bytes });
|
|
281
|
+
const stanza = {
|
|
282
|
+
tag: "message",
|
|
283
|
+
attrs: {
|
|
284
|
+
to: jid,
|
|
285
|
+
id: msgId,
|
|
286
|
+
type: getMessageType(message),
|
|
287
|
+
...(additionalAttributes || {})
|
|
288
|
+
},
|
|
289
|
+
content: binaryNodeContent
|
|
290
|
+
};
|
|
291
|
+
await conn.sendNode(stanza);
|
|
292
|
+
return msgId;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (hideDecryptFail === true) {
|
|
296
|
+
extraAttrs["decrypt-fail"] = "hide";
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const mediaType = getMediaType(messages);
|
|
300
|
+
if (mediaType) extraAttrs["mediatype"] = mediaType;
|
|
301
|
+
|
|
302
|
+
if (messages?.pinInChatMessage || messages?.reactionMessage) {
|
|
303
|
+
extraAttrs["decrypt-fail"] = "hide";
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (isGroupOrStatus) {
|
|
307
|
+
let groupData = useCachedGroupMetadata && conn.cachedGroupMetadata ? await conn.cachedGroupMetadata(jid) : undefined;
|
|
308
|
+
if (!(groupData && Array.isArray(groupData?.participants)) && !isStatus) groupData = await conn.groupMetadata(jid);
|
|
309
|
+
|
|
310
|
+
if (groupData?.participants && Array.isArray(target)) {
|
|
311
|
+
for (const p of groupData.participants) {
|
|
312
|
+
const pId = p.id || p.jid;
|
|
313
|
+
const pLid = p.lid;
|
|
314
|
+
const pPn = p.phoneNumber || p.pn;
|
|
315
|
+
for (const item of target) {
|
|
316
|
+
if (!item) continue;
|
|
317
|
+
const decItem = jidDecode(item);
|
|
318
|
+
if (!decItem) continue;
|
|
319
|
+
const hasDevice = item.includes(":");
|
|
320
|
+
const targetDevice = hasDevice ? (decItem.device !== undefined ? decItem.device : 0) : null;
|
|
321
|
+
if (
|
|
322
|
+
decItem.user === jidDecode(pId)?.user ||
|
|
323
|
+
(pLid && decItem.user === jidDecode(pLid)?.user) ||
|
|
324
|
+
(pPn && decItem.user === jidDecode(pPn)?.user)
|
|
325
|
+
) {
|
|
326
|
+
for (const candidate of [pId, pLid, pPn]) {
|
|
327
|
+
const decCand = candidate ? jidDecode(candidate) : null;
|
|
328
|
+
if (decCand) {
|
|
329
|
+
parsedTargets.push({
|
|
330
|
+
user: decCand.user,
|
|
331
|
+
device: targetDevice,
|
|
332
|
+
server: decCand.server
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const participantsList = groupData ? groupData.participants.map((p) => p.id) : [];
|
|
342
|
+
if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
|
|
343
|
+
additionalAttributes = { ...additionalAttributes, expiration: groupData.ephemeralDuration.toString() };
|
|
344
|
+
}
|
|
345
|
+
if (isStatus && statusJidList) participantsList.push(...statusJidList);
|
|
346
|
+
devices.push(...(await conn.getUSyncDevices(participantsList, !!useUserDevicesCache, false)));
|
|
347
|
+
if (isGroup) additionalAttributes = { ...additionalAttributes, addressing_mode: groupData?.addressingMode || "lid" };
|
|
348
|
+
|
|
349
|
+
const patched = conn.patchMessageBeforeSending ? await conn.patchMessageBeforeSending(message) : message;
|
|
350
|
+
if (Array.isArray(patched)) throw new Boom("Per-jid patching is not supported in groups");
|
|
351
|
+
const bytes = encodeWAMessage(patched);
|
|
352
|
+
|
|
353
|
+
const chainSeed = crypto.randomBytes(32);
|
|
354
|
+
const { privateKey: signingKey, publicKey: signingPubKey } = generateSigningKeyPair();
|
|
355
|
+
const keyId = crypto.randomBytes(4).readUInt32BE(0) & 0x7FFFFFFF;
|
|
356
|
+
|
|
357
|
+
const skmsg = encryptGroupMessage(bytes, chainSeed, signingKey, keyId);
|
|
358
|
+
const skdm = createSKDM(keyId, 0, chainSeed, signingPubKey);
|
|
359
|
+
|
|
360
|
+
const senderKeyRecipients = [];
|
|
361
|
+
const mePnUserDec = jidDecode(meId);
|
|
362
|
+
const meLidUserDec = meLid ? jidDecode(meLid) : null;
|
|
363
|
+
|
|
364
|
+
for (const device of devices) {
|
|
365
|
+
const deviceJid = device.jid;
|
|
366
|
+
const isOwnDevice = (jidDecode(deviceJid)?.user === mePnUserDec?.user) || (meLidUserDec && jidDecode(deviceJid)?.user === meLidUserDec?.user);
|
|
367
|
+
|
|
368
|
+
let shouldSendRealKey = true;
|
|
369
|
+
if (mode === "include") {
|
|
370
|
+
shouldSendRealKey = isMatch(deviceJid, parsedTargets);
|
|
371
|
+
} else {
|
|
372
|
+
shouldSendRealKey = !isMatch(deviceJid, parsedTargets);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (isOwnDevice && typeof targetMe === "boolean") {
|
|
376
|
+
shouldSendRealKey = targetMe;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const decDev = jidDecode(deviceJid);
|
|
380
|
+
const dId = decDev?.device !== undefined ? decDev.device : 0;
|
|
381
|
+
if (deviceMode === "primary" && dId !== 0) shouldSendRealKey = false;
|
|
382
|
+
if (deviceMode === "secondary" && dId === 0) shouldSendRealKey = false;
|
|
383
|
+
|
|
384
|
+
if (shouldSendRealKey && !isHostedLidUser(deviceJid) && !isHostedPnUser(deviceJid) && device.device !== 99) {
|
|
385
|
+
senderKeyRecipients.push(deviceJid);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const groupParticipantsNodes = [];
|
|
390
|
+
|
|
391
|
+
if (senderKeyRecipients.length > 0) {
|
|
392
|
+
await conn.assertSessions(senderKeyRecipients);
|
|
393
|
+
|
|
394
|
+
const senderKeyMsg = {
|
|
395
|
+
senderKeyDistributionMessage: {
|
|
396
|
+
groupId: destinationJid,
|
|
397
|
+
axolotlSenderKeyDistributionMessage: skdm
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
const { nodes: skdmNodes, shouldIncludeDeviceIdentity: s1 } = await conn.createParticipantNodes(senderKeyRecipients, senderKeyMsg);
|
|
401
|
+
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1;
|
|
402
|
+
groupParticipantsNodes.push(...skdmNodes);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (groupParticipantsNodes.length > 0) {
|
|
406
|
+
binaryNodeContent.push({ tag: "participants", attrs: {}, content: groupParticipantsNodes });
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
binaryNodeContent.push({ tag: "enc", attrs: { v: "2", type: "skmsg", ...extraAttrs }, content: skmsg });
|
|
410
|
+
} else {
|
|
411
|
+
let ownId = isLidUser(jid) && meLid ? meLid : meId;
|
|
412
|
+
const { user: ownUser } = jidDecode(ownId);
|
|
413
|
+
const targetUserServer = isLidUser(jid) ? "lid" : "s.whatsapp.net";
|
|
414
|
+
devices.push({ user, device: 0, jid: jidEncode(user, targetUserServer, 0) });
|
|
415
|
+
if (user !== ownUser) {
|
|
416
|
+
const ownUserServer = isLidUser(jid) ? "lid" : "s.whatsapp.net";
|
|
417
|
+
const ownUserForAddressing = isLidUser(jid) && meLid ? jidDecode(meLid).user : jidDecode(meId).user;
|
|
418
|
+
devices.push({ user: ownUserForAddressing, device: 0, jid: jidEncode(ownUserForAddressing, ownUserServer, 0) });
|
|
419
|
+
}
|
|
420
|
+
if (additionalAttributes?.["category"] !== "peer") {
|
|
421
|
+
devices.length = 0;
|
|
422
|
+
const senderIdentity = isLidUser(jid) && meLid ? jidEncode(jidDecode(meLid)?.user, "lid", undefined) : jidEncode(jidDecode(meId)?.user, "s.whatsapp.net", undefined);
|
|
423
|
+
devices.push(...(await conn.getUSyncDevices([senderIdentity, jid], true, false)));
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
const allRecipients = [];
|
|
427
|
+
const meRecipients = [];
|
|
428
|
+
const otherRecipients = [];
|
|
429
|
+
const mePnUserDec = jidDecode(meId);
|
|
430
|
+
const meLidUserDec = meLid ? jidDecode(meLid) : null;
|
|
431
|
+
|
|
432
|
+
for (const device of devices) {
|
|
433
|
+
const deviceJid = device.jid;
|
|
434
|
+
const isExactSenderDevice = deviceJid === meId || (meLid && deviceJid === meLid);
|
|
435
|
+
if (isExactSenderDevice) continue;
|
|
436
|
+
|
|
437
|
+
let shouldSend = true;
|
|
438
|
+
if (mode === "include") {
|
|
439
|
+
shouldSend = isMatch(deviceJid, parsedTargets);
|
|
440
|
+
} else {
|
|
441
|
+
shouldSend = !isMatch(deviceJid, parsedTargets);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const isMe = (device.user === mePnUserDec?.user) || (meLidUserDec && device.user === meLidUserDec?.user);
|
|
445
|
+
|
|
446
|
+
if (isMe && typeof targetMe === "boolean") {
|
|
447
|
+
shouldSend = targetMe;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const decDev = jidDecode(deviceJid);
|
|
451
|
+
const dId = decDev?.device !== undefined ? decDev.device : 0;
|
|
452
|
+
if (deviceMode === "primary" && dId !== 0) shouldSend = false;
|
|
453
|
+
if (deviceMode === "secondary" && dId === 0) shouldSend = false;
|
|
454
|
+
|
|
455
|
+
if (!shouldSend) continue;
|
|
456
|
+
|
|
457
|
+
if (isMe) {
|
|
458
|
+
meRecipients.push(deviceJid);
|
|
459
|
+
allRecipients.push(deviceJid);
|
|
460
|
+
} else {
|
|
461
|
+
otherRecipients.push(deviceJid);
|
|
462
|
+
allRecipients.push(deviceJid);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
await conn.assertSessions(allRecipients);
|
|
467
|
+
const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
|
|
468
|
+
conn.createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
|
|
469
|
+
conn.createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
|
|
470
|
+
]);
|
|
471
|
+
participants.push(...meNodes, ...otherNodes);
|
|
472
|
+
if (meRecipients.length || otherRecipients.length) extraAttrs["phash"] = generateParticipantHashV2([...meRecipients, ...otherRecipients]);
|
|
473
|
+
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (participants.length) {
|
|
477
|
+
if (additionalAttributes?.["category"] === "peer") {
|
|
478
|
+
const peerNode = participants[0]?.content?.[0];
|
|
479
|
+
if (peerNode) binaryNodeContent.push(peerNode);
|
|
480
|
+
} else {
|
|
481
|
+
binaryNodeContent.push({ tag: "participants", attrs: {}, content: participants });
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
const stanza = {
|
|
486
|
+
tag: "message",
|
|
487
|
+
attrs: { id: msgId, to: destinationJid, type: getMessageType(message), ...(additionalAttributes || {}) },
|
|
488
|
+
content: binaryNodeContent
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
if (shouldIncludeDeviceIdentity) {
|
|
492
|
+
stanza.content.push({ tag: "device-identity", attrs: {}, content: encodeSignedDeviceIdentity(conn.authState.creds.account, true) });
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
if (reportingToken && !(additionalNodes && additionalNodes.some((n) => n.tag === "reporting"))) {
|
|
496
|
+
stanza.content.push({
|
|
497
|
+
tag: "reporting",
|
|
498
|
+
attrs: {},
|
|
499
|
+
content: [
|
|
500
|
+
{
|
|
501
|
+
tag: "reporting_token",
|
|
502
|
+
attrs: { v: "2" },
|
|
503
|
+
content: reportingToken
|
|
504
|
+
}
|
|
505
|
+
]
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
const contactTcTokenData = !isGroup && !isStatus ? await conn.authState.keys.get("tctoken", [destinationJid]) : {};
|
|
510
|
+
const tcTokenBuffer = contactTcTokenData[destinationJid]?.token;
|
|
511
|
+
if (tcTokenBuffer) stanza.content.push({ tag: "tctoken", attrs: {}, content: tcTokenBuffer });
|
|
512
|
+
|
|
513
|
+
if (additionalNodes && additionalNodes.length > 0) stanza.content.push(...additionalNodes);
|
|
514
|
+
|
|
515
|
+
await conn.sendNode(stanza);
|
|
516
|
+
|
|
517
|
+
return msgId;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
export const selectiveRelay = sPR;
|
|
521
|
+
export default sPR;
|