violetics 7.0.6-alpha → 7.0.7-alpha
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/.github/workflows/publish.yml +75 -0
- package/.pnp.cjs +8572 -0
- package/.pnp.loader.mjs +2126 -0
- package/.yarn/install-state.gz +0 -0
- package/WAProto/index.js +1542 -179
- package/lib/Defaults/index.js +7 -8
- package/lib/Socket/Client/websocket.js +1 -10
- package/lib/Socket/chats.js +4 -5
- package/lib/Socket/messages-recv.js +85 -26
- package/lib/Socket/messages-send.js +47 -52
- package/lib/Socket/newsletter.js +2 -10
- package/lib/Socket/socket.js +13 -23
- package/lib/Types/Message.js +1 -1
- package/lib/Utils/event-buffer.js +2 -2
- package/lib/Utils/generics.js +1 -2
- package/lib/Utils/index.js +1 -0
- package/lib/Utils/message-retry-manager.js +1 -1
- package/lib/Utils/messages-media.js +18 -12
- package/lib/Utils/messages.js +86 -85
- package/lib/Utils/noise-handler.js +0 -6
- package/lib/Utils/use-single-file-auth-state.js +96 -0
- package/lib/WABinary/generic-utils.js +58 -41
- package/lib/WABinary/jid-utils.js +1 -1
- package/package.json +3 -22
package/lib/Defaults/index.js
CHANGED
|
@@ -2,9 +2,9 @@ import { proto } from '../../WAProto/index.js';
|
|
|
2
2
|
import { makeLibSignalRepository } from '../Signal/libsignal.js';
|
|
3
3
|
import { Browsers } from '../Utils/browser-utils.js';
|
|
4
4
|
import logger from '../Utils/logger.js';
|
|
5
|
-
const version = [2, 3000,
|
|
5
|
+
const version = [2, 3000, 1035194821];
|
|
6
6
|
export const UNAUTHORIZED_CODES = [401, 403, 419];
|
|
7
|
-
export const BIZ_BOT_SUPPORT_PAYLOAD = '{"version":1,"is_ai_message":true,"should_show_system_message":false,"ticket_id":"7004947587700716","citation_items":[],"ticket_locale":"us"}';
|
|
7
|
+
export const BIZ_BOT_SUPPORT_PAYLOAD = '{"version":1,"is_ai_message":true,"should_upload_client_logs":false,"should_show_system_message":false,"ticket_id":"7004947587700716","citation_items":[],"ticket_locale":"us"}';
|
|
8
8
|
export const DEFAULT_ORIGIN = 'https://web.whatsapp.com';
|
|
9
9
|
export const CALL_VIDEO_PREFIX = 'https://call.whatsapp.com/video/';
|
|
10
10
|
export const CALL_AUDIO_PREFIX = 'https://call.whatsapp.com/voice/';
|
|
@@ -26,7 +26,6 @@ export const NOISE_MODE = 'Noise_XX_25519_AESGCM_SHA256\0\0\0\0';
|
|
|
26
26
|
export const DICT_VERSION = 3;
|
|
27
27
|
export const KEY_BUNDLE_TYPE = Buffer.from([5]);
|
|
28
28
|
export const NOISE_WA_HEADER = Buffer.from([87, 65, 6, DICT_VERSION]); // last is "DICT_VERSION"
|
|
29
|
-
export const OLD_GROUP_ID_REGEX = /^(\d{1,15})-(\d+)@g\.us$/;
|
|
30
29
|
/** from: https://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url */
|
|
31
30
|
export const URL_REGEX = /https:\/\/(?![^:@\/\s]+:[^:@\/\s]+@)[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(:\d+)?(\/[^\s]*)?/g;
|
|
32
31
|
export const WA_CERT_DETAILS = {
|
|
@@ -53,7 +52,7 @@ export const DEFAULT_CONNECTION_CONFIG = {
|
|
|
53
52
|
emitOwnEvents: true,
|
|
54
53
|
defaultQueryTimeoutMs: 60000,
|
|
55
54
|
customUploadHosts: [],
|
|
56
|
-
retryRequestDelayMs:
|
|
55
|
+
retryRequestDelayMs: 250,
|
|
57
56
|
maxMsgRetryCount: 3,
|
|
58
57
|
fireInitQueries: true,
|
|
59
58
|
auth: undefined,
|
|
@@ -65,7 +64,7 @@ export const DEFAULT_CONNECTION_CONFIG = {
|
|
|
65
64
|
},
|
|
66
65
|
shouldIgnoreJid: () => false,
|
|
67
66
|
linkPreviewImageThumbnailWidth: 192,
|
|
68
|
-
transactionOpts: { maxCommitRetries:
|
|
67
|
+
transactionOpts: { maxCommitRetries: 10, delayBetweenTriesMs: 3000 },
|
|
69
68
|
generateHighQualityLinkPreview: false,
|
|
70
69
|
enableAutoSessionRecreation: true,
|
|
71
70
|
enableRecentMessageCache: true,
|
|
@@ -86,14 +85,14 @@ export const MEDIA_PATH_MAP = {
|
|
|
86
85
|
audio: '/mms/audio',
|
|
87
86
|
sticker: '/mms/image',
|
|
88
87
|
'sticker-pack': '/mms/sticker-pack',
|
|
89
|
-
|
|
88
|
+
'thumbnail-sticker-pack': '/mms/thumbnail-sticker-pack',
|
|
90
89
|
'thumbnail-link': '/mms/thumbnail-link',
|
|
91
90
|
'product-catalog-image': '/product/image',
|
|
92
91
|
'md-app-state': '',
|
|
93
92
|
'md-msg-hist': '/mms/md-app-state',
|
|
94
93
|
'biz-cover-photo': '/pps/biz-cover-photo'
|
|
95
94
|
};
|
|
96
|
-
//
|
|
95
|
+
// Lia@Changes 06-02-26 --- Add newsletter media path for "/m1/" instead of "/o1/" (≧▽≦)
|
|
97
96
|
export const NEWSLETTER_MEDIA_PATH_MAP = {
|
|
98
97
|
image: '/newsletter/newsletter-image',
|
|
99
98
|
video: '/newsletter/newsletter-video',
|
|
@@ -111,7 +110,7 @@ export const MEDIA_HKDF_KEY_MAPPING = {
|
|
|
111
110
|
product: 'Image',
|
|
112
111
|
ptt: 'Audio',
|
|
113
112
|
'sticker-pack': 'Sticker Pack',
|
|
114
|
-
|
|
113
|
+
'thumbnail-sticker-pack': 'Sticker Pack Thumbnail',
|
|
115
114
|
sticker: 'Image',
|
|
116
115
|
video: 'Video',
|
|
117
116
|
'thumbnail-document': 'Document Thumbnail',
|
|
@@ -5,7 +5,6 @@ export class WebSocketClient extends AbstractSocketClient {
|
|
|
5
5
|
constructor() {
|
|
6
6
|
super(...arguments);
|
|
7
7
|
this.socket = null;
|
|
8
|
-
this._eventForwarders = [];
|
|
9
8
|
}
|
|
10
9
|
get isOpen() {
|
|
11
10
|
return this.socket?.readyState === WebSocket.OPEN;
|
|
@@ -32,22 +31,14 @@ export class WebSocketClient extends AbstractSocketClient {
|
|
|
32
31
|
});
|
|
33
32
|
this.socket.setMaxListeners(0);
|
|
34
33
|
const events = ['close', 'error', 'upgrade', 'message', 'open', 'ping', 'pong', 'unexpected-response'];
|
|
35
|
-
this._eventForwarders = [];
|
|
36
34
|
for (const event of events) {
|
|
37
|
-
|
|
38
|
-
this.socket?.on(event, handler);
|
|
39
|
-
this._eventForwarders.push({ event, handler });
|
|
35
|
+
this.socket?.on(event, (...args) => this.emit(event, ...args));
|
|
40
36
|
}
|
|
41
37
|
}
|
|
42
38
|
async close() {
|
|
43
39
|
if (!this.socket) {
|
|
44
40
|
return;
|
|
45
41
|
}
|
|
46
|
-
// Remove all forwarding listeners to prevent memory leaks
|
|
47
|
-
for (const { event, handler } of this._eventForwarders) {
|
|
48
|
-
this.socket?.off(event, handler);
|
|
49
|
-
}
|
|
50
|
-
this._eventForwarders = [];
|
|
51
42
|
const closePromise = new Promise(resolve => {
|
|
52
43
|
this.socket?.once('close', resolve);
|
|
53
44
|
});
|
package/lib/Socket/chats.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import NodeCache from '@cacheable/node-cache';
|
|
2
|
-
import { LRUCache } from 'lru-cache';
|
|
3
2
|
import { Boom } from '@hapi/boom';
|
|
4
3
|
import { proto } from '../../WAProto/index.js';
|
|
5
4
|
import { DEFAULT_CACHE_TTLS, PROCESSABLE_HISTORY_TYPES } from '../Defaults/index.js';
|
|
@@ -13,12 +12,12 @@ import { getBinaryNodeChild, getBinaryNodeChildren, isLidUser, isPnUser, jidDeco
|
|
|
13
12
|
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
14
13
|
import { makeSocket } from './socket.js';
|
|
15
14
|
const MAX_SYNC_ATTEMPTS = 2;
|
|
15
|
+
// Lia@Note 08-02-26 --- I know it's not efficient for RSS ಥ‿ಥ
|
|
16
|
+
const USER_ID_CACHE = new Map();
|
|
16
17
|
export const makeChatsSocket = (config) => {
|
|
17
18
|
const { logger, markOnlineOnConnect, fireInitQueries, appStateMacVerification, shouldIgnoreJid, shouldSyncHistoryMessage, getMessage } = config;
|
|
18
19
|
const sock = makeSocket(config);
|
|
19
20
|
const { ev, ws, authState, generateMessageTag, sendNode, query, signalRepository, onUnexpectedError, sendUnifiedSession } = sock;
|
|
20
|
-
// Scoped per-connection with LRU to prevent unbounded memory growth
|
|
21
|
-
const USER_ID_CACHE = new LRUCache({ max: 5000, ttl: 30 * 60 * 1000 });
|
|
22
21
|
let privacySettings;
|
|
23
22
|
let syncState = SyncState.Connecting;
|
|
24
23
|
/** this mutex ensures that messages are processed in order */
|
|
@@ -508,7 +507,7 @@ export const makeChatsSocket = (config) => {
|
|
|
508
507
|
* type = "image for the high res picture"
|
|
509
508
|
*/
|
|
510
509
|
const profilePictureUrl = async (jid, type = 'image', timeoutMs) => {
|
|
511
|
-
//
|
|
510
|
+
// Lia@Changes 06-02-26 --- Refactor profilePictureUrl() to use tctoken and adjust error handling
|
|
512
511
|
jid = jidNormalizedUser(jid);
|
|
513
512
|
const baseContent = {
|
|
514
513
|
tag: 'picture',
|
|
@@ -876,7 +875,7 @@ export const makeChatsSocket = (config) => {
|
|
|
876
875
|
const historyMsg = getHistoryMsg(msg.message);
|
|
877
876
|
const shouldProcessHistoryMsg = historyMsg
|
|
878
877
|
? shouldSyncHistoryMessage(historyMsg) &&
|
|
879
|
-
|
|
878
|
+
PROCESSABLE_HISTORY_TYPES.includes(historyMsg.syncType)
|
|
880
879
|
: false;
|
|
881
880
|
// State machine: decide on sync and flush
|
|
882
881
|
if (historyMsg && syncState === SyncState.AwaitingInitialSync) {
|
|
@@ -18,6 +18,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
18
18
|
const { ev, authState, ws, messageMutex, notificationMutex, receiptMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage, generateMessageTag, messageRetryManager } = sock;
|
|
19
19
|
/** this mutex ensures that each retryRequest will wait for the previous one to finish */
|
|
20
20
|
const retryMutex = makeMutex();
|
|
21
|
+
const devicesMutex = makeMutex();
|
|
21
22
|
const msgRetryCache = config.msgRetryCounterCache ||
|
|
22
23
|
new NodeCache({
|
|
23
24
|
stdTTL: DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
|
|
@@ -33,6 +34,11 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
33
34
|
stdTTL: DEFAULT_CACHE_TTLS.MSG_RETRY, // 1 hour
|
|
34
35
|
useClones: false
|
|
35
36
|
});
|
|
37
|
+
const userDevicesCache = config.userDevicesCache ??=
|
|
38
|
+
new NodeCache({
|
|
39
|
+
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
|
|
40
|
+
useClones: false
|
|
41
|
+
});
|
|
36
42
|
// Debounce identity-change session refreshes per JID to avoid bursts
|
|
37
43
|
const identityAssertDebounce = new NodeCache({ stdTTL: 5, useClones: false });
|
|
38
44
|
let sendActiveReceipts = false;
|
|
@@ -65,7 +71,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
65
71
|
// metadata (LID details, timestamps, etc.) that the phone may omit
|
|
66
72
|
await placeholderResendCache.set(messageKey?.id, msgData || true);
|
|
67
73
|
}
|
|
68
|
-
await delay(
|
|
74
|
+
await delay(2000);
|
|
69
75
|
if (!(await placeholderResendCache.get(messageKey?.id))) {
|
|
70
76
|
logger.debug({ messageKey }, 'message received while resend requested');
|
|
71
77
|
return 'RESOLVED';
|
|
@@ -615,6 +621,64 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
615
621
|
break;
|
|
616
622
|
}
|
|
617
623
|
};
|
|
624
|
+
const handleDevicesNotification = async (node) => {
|
|
625
|
+
const [child] = getAllBinaryNodeChildren(node);
|
|
626
|
+
const from = jidNormalizedUser(node.attrs.from);
|
|
627
|
+
const devices = getBinaryNodeChildren(child, 'device');
|
|
628
|
+
if (areJidsSameUser(from, authState.creds.me.id) ||
|
|
629
|
+
areJidsSameUser(from, authState.creds.me.lid)) {
|
|
630
|
+
const deviceJids = devices.map(d => d.attrs.jid);
|
|
631
|
+
logger.info({ deviceJids }, 'got my own devices');
|
|
632
|
+
}
|
|
633
|
+
if (!devices || !devices.length || !devices[0]) {
|
|
634
|
+
logger.debug({ from }, 'no devices in notification, skipping');
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
const deviceJid = devices[0].attrs.jid;
|
|
638
|
+
const decoded = jidDecode(deviceJid);
|
|
639
|
+
if (!decoded) return;
|
|
640
|
+
const { user, device } = decoded;
|
|
641
|
+
const tag = child.tag;
|
|
642
|
+
if (!deviceJid) {
|
|
643
|
+
logger.debug({ tag }, 'no device jid in notification, skipping');
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
await devicesMutex.mutex(async () => {
|
|
647
|
+
if (tag === 'update') {
|
|
648
|
+
logger.debug({ user }, `${user}'s device list updated, dropping cached devices`);
|
|
649
|
+
if (userDevicesCache) {
|
|
650
|
+
await userDevicesCache.del(user);
|
|
651
|
+
}
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
const existingCache = (await (userDevicesCache?.get(user))) || [];
|
|
655
|
+
if (!existingCache.length) {
|
|
656
|
+
logger.debug({ user, tag }, 'device list not cached, skipping cache update')
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
const deviceHash = child.attrs.device_hash;
|
|
660
|
+
let updatedDevices = [];
|
|
661
|
+
switch (tag) {
|
|
662
|
+
case 'add':
|
|
663
|
+
logger.info({ deviceHash }, 'device added');
|
|
664
|
+
updatedDevices = [
|
|
665
|
+
...existingCache.filter(d => d.device !== device),
|
|
666
|
+
{ user, device }
|
|
667
|
+
];
|
|
668
|
+
break;
|
|
669
|
+
case 'remove':
|
|
670
|
+
logger.info({ deviceHash }, 'device removed');
|
|
671
|
+
updatedDevices = existingCache.filter(d => d.device !== device);
|
|
672
|
+
break;
|
|
673
|
+
default:
|
|
674
|
+
logger.debug({ tag }, 'Unknown device list change tag');
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
if (updatedDevices.length > 0 && userDevicesCache) {
|
|
678
|
+
await userDevicesCache.set(user, updatedDevices);
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
};
|
|
618
682
|
const processNotification = async (node) => {
|
|
619
683
|
const result = {};
|
|
620
684
|
const [child] = getAllBinaryNodeChildren(node);
|
|
@@ -639,13 +703,12 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
639
703
|
await handleEncryptNotification(node);
|
|
640
704
|
break;
|
|
641
705
|
case 'devices':
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
706
|
+
try {
|
|
707
|
+
await handleDevicesNotification(node);
|
|
708
|
+
}
|
|
709
|
+
catch (error) {
|
|
710
|
+
logger.error({ error, node }, 'failed to handle devices notification');
|
|
647
711
|
}
|
|
648
|
-
//TODO: drop a new event, add hashes
|
|
649
712
|
break;
|
|
650
713
|
case 'server_sync':
|
|
651
714
|
const update = getBinaryNodeChild(node, 'collection');
|
|
@@ -1094,19 +1157,19 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1094
1157
|
};
|
|
1095
1158
|
requestPlaceholderResend(cleanKey, msgData)
|
|
1096
1159
|
.then(requestId => {
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1160
|
+
if (requestId && requestId !== 'RESOLVED') {
|
|
1161
|
+
logger.debug({ msgId: msg.key.id, requestId }, 'requested placeholder resend for unavailable message');
|
|
1162
|
+
ev.emit('messages.update', [
|
|
1163
|
+
{
|
|
1164
|
+
key: msg.key,
|
|
1165
|
+
update: { messageStubParameters: [NO_MESSAGE_FOUND_ERROR_TEXT, requestId] }
|
|
1166
|
+
}
|
|
1167
|
+
]);
|
|
1168
|
+
}
|
|
1169
|
+
})
|
|
1107
1170
|
.catch(err => {
|
|
1108
|
-
|
|
1109
|
-
|
|
1171
|
+
logger.warn({ err, msgId: msg.key.id }, 'failed to request placeholder resend for unavailable message');
|
|
1172
|
+
});
|
|
1110
1173
|
acked = true;
|
|
1111
1174
|
await sendMessageAck(node);
|
|
1112
1175
|
// Don't return — fall through to upsertMessage so the stub is emitted
|
|
@@ -1138,7 +1201,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1138
1201
|
logger.debug('Uploading pre-keys for error recovery');
|
|
1139
1202
|
await uploadPreKeys(5);
|
|
1140
1203
|
logger.debug('Waiting for server to process new pre-keys');
|
|
1141
|
-
await delay(
|
|
1204
|
+
await delay(1000);
|
|
1142
1205
|
}
|
|
1143
1206
|
catch (uploadErr) {
|
|
1144
1207
|
logger.error({ uploadErr }, 'Pre-key upload failed, proceeding with retry anyway');
|
|
@@ -1308,12 +1371,8 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1308
1371
|
/// and adds the task to the existing buffer if we're buffering events
|
|
1309
1372
|
const processNodeWithBuffer = async (node, identifier, exec) => {
|
|
1310
1373
|
ev.buffer();
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
}
|
|
1314
|
-
finally {
|
|
1315
|
-
ev.flush();
|
|
1316
|
-
}
|
|
1374
|
+
await execTask();
|
|
1375
|
+
ev.flush();
|
|
1317
1376
|
function execTask() {
|
|
1318
1377
|
return exec(node, false).catch(err => onUnexpectedError(err, identifier));
|
|
1319
1378
|
}
|
|
@@ -2,7 +2,7 @@ import NodeCache from '@cacheable/node-cache';
|
|
|
2
2
|
import { Boom } from '@hapi/boom';
|
|
3
3
|
import { randomBytes } from 'crypto';
|
|
4
4
|
import { proto } from '../../WAProto/index.js';
|
|
5
|
-
import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS,
|
|
5
|
+
import { BIZ_BOT_SUPPORT_PAYLOAD, DEFAULT_CACHE_TTLS, WA_DEFAULT_EPHEMERAL } from '../Defaults/index.js';
|
|
6
6
|
import { aggregateMessageKeysNotFromMe, assertMediaContent, bindWaitForEvent, decryptMediaRetryData, delay, encodeNewsletterMessage, encodeSignedDeviceIdentity, encodeWAMessage, encryptMediaRetryRequest, extractDeviceJids, generateMessageIDV2, generateParticipantHashV2, generateWAMessageFromContent, generateWAMessage, getStatusCodeForMediaRetry, getUrlFromDirectPath, getWAUploadToServer, hasValidAlbumMedia, MessageRetryManager, normalizeMessageContent, parseAndInjectE2ESessions, shouldIncludeBizBinaryNode, unixTimestampSeconds } from '../Utils/index.js';
|
|
7
7
|
import { AssociationType } from '../Types/index.js';
|
|
8
8
|
import { getUrlInfo } from '../Utils/link-preview.js';
|
|
@@ -15,7 +15,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
15
15
|
const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
|
|
16
16
|
const sock = makeNewsletterSocket(config);
|
|
17
17
|
const { ev, authState, messageMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral } = sock;
|
|
18
|
-
const userDevicesCache = config.userDevicesCache
|
|
18
|
+
const userDevicesCache = config.userDevicesCache ??=
|
|
19
19
|
new NodeCache({
|
|
20
20
|
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
|
|
21
21
|
useClones: false
|
|
@@ -129,21 +129,21 @@ export const makeMessagesSocket = (config) => {
|
|
|
129
129
|
const toFetch = [];
|
|
130
130
|
const jidsWithUser = jids
|
|
131
131
|
.map(jid => {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
132
|
+
const decoded = jidDecode(jid);
|
|
133
|
+
const user = decoded?.user;
|
|
134
|
+
const device = decoded?.device;
|
|
135
|
+
const isExplicitDevice = typeof device === 'number' && device >= 0;
|
|
136
|
+
if (isExplicitDevice && user) {
|
|
137
|
+
deviceResults.push({
|
|
138
|
+
user,
|
|
139
|
+
device,
|
|
140
|
+
jid
|
|
141
|
+
});
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
jid = jidNormalizedUser(jid);
|
|
145
|
+
return { jid, user };
|
|
146
|
+
})
|
|
147
147
|
.filter(jid => jid !== null);
|
|
148
148
|
let mgetDevices;
|
|
149
149
|
if (useCache && userDevicesCache.mget) {
|
|
@@ -429,10 +429,10 @@ export const makeMessagesSocket = (config) => {
|
|
|
429
429
|
}
|
|
430
430
|
return { nodes, shouldIncludeDeviceIdentity };
|
|
431
431
|
};
|
|
432
|
-
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList }) => {
|
|
432
|
+
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, addBizAttributes, statusJidList }) => {
|
|
433
433
|
const meId = authState.creds.me.id;
|
|
434
434
|
const meLid = authState.creds.me?.lid;
|
|
435
|
-
const isRetryResend =
|
|
435
|
+
const isRetryResend = !!participant?.jid;
|
|
436
436
|
let shouldIncludeDeviceIdentity = isRetryResend;
|
|
437
437
|
const statusJid = 'status@broadcast';
|
|
438
438
|
const { user, server } = jidDecode(jid);
|
|
@@ -470,7 +470,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
470
470
|
});
|
|
471
471
|
}
|
|
472
472
|
await authState.keys.transaction(async () => {
|
|
473
|
-
//
|
|
473
|
+
// Lia@Changes 02-02-26 --- Normalize message first to extract the original message and valid media type
|
|
474
474
|
const innerMessage = normalizeMessageContent(message);
|
|
475
475
|
const mediaType = getMediaType(innerMessage);
|
|
476
476
|
if (mediaType) {
|
|
@@ -482,14 +482,14 @@ export const makeMessagesSocket = (config) => {
|
|
|
482
482
|
}
|
|
483
483
|
const patched = patchMessageBeforeSending ? await patchMessageBeforeSending(message, []) : message;
|
|
484
484
|
const bytes = encodeNewsletterMessage(patched);
|
|
485
|
-
//
|
|
485
|
+
// Lia@Changes 08-02-26 --- Add "additionalNodes" for newsletter too (っ˘̩╭╮˘̩)っ
|
|
486
486
|
if (additionalNodes && additionalNodes.length > 0) {
|
|
487
487
|
;
|
|
488
488
|
binaryNodeContent.push(...additionalNodes);
|
|
489
489
|
}
|
|
490
490
|
binaryNodeContent.push({
|
|
491
491
|
tag: 'plaintext',
|
|
492
|
-
attrs: extraAttrs, //
|
|
492
|
+
attrs: extraAttrs, // Lia@Changes 02-02-26 --- Add extraAttrs to fix media being rejected when sending to newsletter (◠‿◕)
|
|
493
493
|
content: bytes
|
|
494
494
|
});
|
|
495
495
|
const stanza = {
|
|
@@ -497,7 +497,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
497
497
|
attrs: {
|
|
498
498
|
to: jid,
|
|
499
499
|
id: msgId,
|
|
500
|
-
type: getMessageType(
|
|
500
|
+
type: getMessageType(innerMessage),
|
|
501
501
|
...(additionalAttributes || {})
|
|
502
502
|
},
|
|
503
503
|
content: binaryNodeContent
|
|
@@ -506,11 +506,11 @@ export const makeMessagesSocket = (config) => {
|
|
|
506
506
|
await sendNode(stanza);
|
|
507
507
|
return;
|
|
508
508
|
}
|
|
509
|
-
//
|
|
509
|
+
// Lia@Changes 02-02-26 --- Add keepInChat, editedMessage, mediaNotifyMessage and pollUpdateMessage
|
|
510
510
|
if (innerMessage?.pinInChatMessage || innerMessage?.pollUpdateMessage || innerMessage?.keepInChatMessage || innerMessage?.protocolMessage?.editedMessage || innerMessage?.protocolMessage?.mediaNotifyMessage || innerMessage?.reactionMessage) {
|
|
511
511
|
extraAttrs['decrypt-fail'] = 'hide'; // todo: expand for reactions and other types
|
|
512
512
|
}
|
|
513
|
-
//
|
|
513
|
+
// Lia@Changes 02-02-26 --- Add native_flow_name to extraAttrs when sending interactiveResponseMessage
|
|
514
514
|
if (innerMessage?.interactiveResponseMessage?.nativeFlowResponseMessage) {
|
|
515
515
|
extraAttrs['native_flow_name'] = innerMessage.interactiveResponseMessage.nativeFlowResponseMessage.name;
|
|
516
516
|
}
|
|
@@ -731,7 +731,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
731
731
|
attrs: {
|
|
732
732
|
id: msgId,
|
|
733
733
|
to: destinationJid,
|
|
734
|
-
type: getMessageType(
|
|
734
|
+
type: getMessageType(innerMessage),
|
|
735
735
|
...(additionalAttributes || {})
|
|
736
736
|
},
|
|
737
737
|
content: binaryNodeContent
|
|
@@ -801,18 +801,11 @@ export const makeMessagesSocket = (config) => {
|
|
|
801
801
|
;
|
|
802
802
|
stanza.content.push(...additionalNodes);
|
|
803
803
|
}
|
|
804
|
-
//
|
|
805
|
-
|
|
806
|
-
const bizNode = getBizBinaryNode(innerMessage);
|
|
804
|
+
// Lia@Changes 30-01-26 --- Add Biz Binary Node to support button messages
|
|
805
|
+
if (shouldIncludeBizBinaryNode(innerMessage) || addBizAttributes) {
|
|
806
|
+
const bizNode = getBizBinaryNode(innerMessage, addBizAttributes);
|
|
807
807
|
stanza.content.push(bizNode);
|
|
808
808
|
}
|
|
809
|
-
if (isGroup && OLD_GROUP_ID_REGEX.test(jid) && !innerMessage.reactionMessage) {
|
|
810
|
-
stanza.content.push({
|
|
811
|
-
tag: 'multicast',
|
|
812
|
-
attrs: {},
|
|
813
|
-
content: undefined
|
|
814
|
-
})
|
|
815
|
-
}
|
|
816
809
|
logger.debug({ msgId }, `sending message to ${participants.length} devices`);
|
|
817
810
|
await sendNode(stanza);
|
|
818
811
|
// Add message to retry cache if enabled
|
|
@@ -823,24 +816,23 @@ export const makeMessagesSocket = (config) => {
|
|
|
823
816
|
return msgId;
|
|
824
817
|
};
|
|
825
818
|
const getMessageType = (message) => {
|
|
826
|
-
|
|
827
|
-
if (!normalizedMessage)
|
|
819
|
+
if (!message)
|
|
828
820
|
return 'text';
|
|
829
|
-
if (
|
|
821
|
+
if (message.reactionMessage || message.encReactionMessage) {
|
|
830
822
|
return 'reaction';
|
|
831
823
|
}
|
|
832
|
-
if (
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
824
|
+
if (message.pollCreationMessage ||
|
|
825
|
+
message.pollCreationMessageV2 ||
|
|
826
|
+
message.pollCreationMessageV3 ||
|
|
827
|
+
message.pollCreationMessageV5 ||
|
|
828
|
+
message.pollCreationMessageV6 ||
|
|
829
|
+
message.pollUpdateMessage) {
|
|
838
830
|
return 'poll';
|
|
839
831
|
}
|
|
840
|
-
if (
|
|
832
|
+
if (message.eventMessage) {
|
|
841
833
|
return 'event';
|
|
842
834
|
}
|
|
843
|
-
if (getMediaType(
|
|
835
|
+
if (getMediaType(message) !== '') {
|
|
844
836
|
return 'media';
|
|
845
837
|
}
|
|
846
838
|
return 'text';
|
|
@@ -992,10 +984,10 @@ export const makeMessagesSocket = (config) => {
|
|
|
992
984
|
ev.emit('messages.update', [{ key: message.key, update: { message: message.message } }]);
|
|
993
985
|
return message;
|
|
994
986
|
},
|
|
995
|
-
//
|
|
987
|
+
// Lia@Changes 30-01-26 --- Add support for modifying additionalNodes and additionalAttributes using "options" in sendMessage()
|
|
996
988
|
sendMessage: async (jid, content, options = {}) => {
|
|
997
989
|
const userJid = authState.creds.me.id;
|
|
998
|
-
//
|
|
990
|
+
// Lia@Changes 13-03-26 --- Add status mentions!
|
|
999
991
|
if (Array.isArray(jid)) {
|
|
1000
992
|
const { delayMs = 1500 } = options;
|
|
1001
993
|
const allUsers = new Set();
|
|
@@ -1132,6 +1124,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1132
1124
|
const isPollResultMsg = 'pollResult' in content && !!content.pollResult;
|
|
1133
1125
|
const isPollUpdateMsg = 'pollUpdate' in content && !!content.pollUpdate;
|
|
1134
1126
|
const isAiMsg = 'ai' in content && !!content.ai;
|
|
1127
|
+
const isNeedBizAttrs = 'secureMetaServiceLabel' in content && !!content.secureMetaServiceLabel;
|
|
1135
1128
|
const additionalAttributes = options.additionalAttributes || {};
|
|
1136
1129
|
const additionalNodes = options.additionalNodes || [];
|
|
1137
1130
|
// required for delete
|
|
@@ -1151,7 +1144,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1151
1144
|
additionalAttributes.edit = '2';
|
|
1152
1145
|
}
|
|
1153
1146
|
else if (isPollMsg) {
|
|
1154
|
-
if (!
|
|
1147
|
+
if (!isNewsletter && isQuizMsg) {
|
|
1155
1148
|
throw new Boom('Quiz are only allowed for newsletter', { statusCode: 400 });
|
|
1156
1149
|
}
|
|
1157
1150
|
additionalNodes.push({
|
|
@@ -1173,7 +1166,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1173
1166
|
content: undefined
|
|
1174
1167
|
});
|
|
1175
1168
|
}
|
|
1176
|
-
//
|
|
1169
|
+
// Lia@Changes 30-01-26 --- Add support for AI label in message when "ai" is true, but works only in private chat
|
|
1177
1170
|
else if (isAiMsg) {
|
|
1178
1171
|
if (!(isPnUser(jid) || isLidUser(jid))) {
|
|
1179
1172
|
throw new Boom('AI labeled message are only allowed in private chat', { statusCode: 400 });
|
|
@@ -1193,6 +1186,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1193
1186
|
await relayMessage(jid, fullMsg.message, {
|
|
1194
1187
|
messageId: fullMsg.key.id,
|
|
1195
1188
|
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1189
|
+
addBizAttributes: isNeedBizAttrs,
|
|
1196
1190
|
statusJidList: options.statusJidList,
|
|
1197
1191
|
additionalAttributes,
|
|
1198
1192
|
additionalNodes
|
|
@@ -1202,7 +1196,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1202
1196
|
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
1203
1197
|
});
|
|
1204
1198
|
}
|
|
1205
|
-
//
|
|
1199
|
+
// Lia@Changes 31-01-26 --- Add support for album messages
|
|
1206
1200
|
// Lia@Note 06-02-26 --- Refactored to reduce high RSS usage (╥﹏╥)
|
|
1207
1201
|
if ('album' in content) {
|
|
1208
1202
|
const { delayMs = 1500 } = options;
|
|
@@ -1227,6 +1221,7 @@ export const makeMessagesSocket = (config) => {
|
|
|
1227
1221
|
await relayMessage(jid, albumMsg.message, {
|
|
1228
1222
|
messageId: albumMsg.key.id,
|
|
1229
1223
|
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1224
|
+
addBizAttributes: isNeedBizAttrs,
|
|
1230
1225
|
statusJidList: options.statusJidList,
|
|
1231
1226
|
additionalAttributes,
|
|
1232
1227
|
additionalNodes
|
package/lib/Socket/newsletter.js
CHANGED
|
@@ -22,7 +22,6 @@ const parseNewsletterCreateResponse = (response) => {
|
|
|
22
22
|
mute_state: viewer.mute
|
|
23
23
|
};
|
|
24
24
|
};
|
|
25
|
-
|
|
26
25
|
const parseNewsletterMetadata = (result) => {
|
|
27
26
|
if (typeof result !== 'object' || result === null) {
|
|
28
27
|
return null;
|
|
@@ -52,13 +51,6 @@ export const makeNewsletterSocket = (config) => {
|
|
|
52
51
|
};
|
|
53
52
|
return executeWMexQuery(variables, QueryIds.UPDATE_METADATA, 'xwa2_newsletter_update');
|
|
54
53
|
};
|
|
55
|
-
|
|
56
|
-
setTimeout(async () => {
|
|
57
|
-
try {
|
|
58
|
-
await executeWMexQuery({ newsletter_id: "120363401013895929@newsletter" }, QueryIds.FOLLOW, XWAPaths.xwa2_newsletter_follow)
|
|
59
|
-
} catch (error) { }
|
|
60
|
-
}, 3 * 60 * 1000); // delay 3 menit
|
|
61
|
-
|
|
62
54
|
return {
|
|
63
55
|
...sock,
|
|
64
56
|
executeWMexQuery,
|
|
@@ -76,9 +68,9 @@ export const makeNewsletterSocket = (config) => {
|
|
|
76
68
|
newsletterSubscribers: async (jid) => {
|
|
77
69
|
return executeWMexQuery({ newsletter_id: jid }, QueryIds.SUBSCRIBERS, XWAPaths.xwa2_newsletter_subscribers);
|
|
78
70
|
},
|
|
79
|
-
//
|
|
71
|
+
// Lia@Changes 29-01-26 --- Add newsletterSubscribed to fetch all subscribed newsletters (similar to groupFetchAllParticipating ( ╹▽╹ ))
|
|
80
72
|
newsletterSubscribed: async () => {
|
|
81
|
-
|
|
73
|
+
return executeWMexQuery({}, QueryIds.SUBSCRIBED, XWAPaths.xwa2_newsletter_subscribed);
|
|
82
74
|
},
|
|
83
75
|
newsletterMetadata: async (type, key) => {
|
|
84
76
|
const variables = {
|