socketon 0.31.0 → 1.51.16
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 +313 -159
- package/WAProto/WAProto.proto +5311 -0
- package/WAProto/index.js +65801 -141371
- package/lib/Defaults/index.js +117 -141
- package/lib/KeyDB/BinarySearch.js +20 -0
- package/lib/KeyDB/KeyedDB.js +167 -0
- package/lib/KeyDB/index.js +4 -0
- package/lib/Signal/Group/ciphertext-message.js +12 -14
- package/lib/Signal/Group/group-session-builder.js +10 -42
- package/lib/Signal/Group/group_cipher.js +75 -87
- package/lib/Signal/Group/index.js +13 -57
- package/lib/Signal/Group/keyhelper.js +17 -52
- package/lib/Signal/Group/sender-chain-key.js +27 -33
- package/lib/Signal/Group/sender-key-distribution-message.js +62 -63
- package/lib/Signal/Group/sender-key-message.js +65 -66
- package/lib/Signal/Group/sender-key-name.js +45 -44
- package/lib/Signal/Group/sender-key-record.js +39 -49
- package/lib/Signal/Group/sender-key-state.js +80 -93
- package/lib/Signal/Group/sender-message-key.js +27 -28
- package/lib/Signal/libsignal.js +313 -163
- package/lib/Signal/lid-mapping.js +155 -0
- package/lib/Socket/Client/index.js +4 -19
- package/lib/Socket/Client/types.js +13 -0
- package/lib/Socket/Client/websocket.js +52 -0
- package/lib/Socket/Client/websocket.js.bak +53 -0
- package/lib/Socket/business.js +359 -242
- package/lib/Socket/chats.js +846 -935
- package/lib/Socket/communities.js +413 -0
- package/lib/Socket/groups.js +304 -309
- package/lib/Socket/index.js +15 -10
- package/lib/Socket/messages-recv.js +1107 -1054
- package/lib/Socket/messages-send.js +639 -448
- package/lib/Socket/mex.js +45 -0
- package/lib/Socket/newsletter.js +270 -282
- package/lib/Socket/socket.js +798 -635
- package/lib/Socket/socketon.js +402 -0
- package/lib/Store/index.js +6 -10
- package/lib/Store/make-cache-manager-store.js +73 -81
- package/lib/Store/make-in-memory-store.js +286 -423
- package/lib/Store/make-ordered-dictionary.js +77 -79
- package/lib/Store/object-repository.js +24 -26
- package/lib/Types/Auth.js +3 -2
- package/lib/Types/Bussines.js +3 -0
- package/lib/Types/Call.js +3 -2
- package/lib/Types/Chat.js +9 -4
- package/lib/Types/Contact.js +3 -2
- package/lib/Types/Events.js +3 -2
- package/lib/Types/GroupMetadata.js +3 -2
- package/lib/Types/Label.js +24 -26
- package/lib/Types/LabelAssociation.js +6 -8
- package/lib/Types/Message.js +12 -9
- package/lib/Types/Newsletter.js +33 -38
- package/lib/Types/Newsletter.js.bak +33 -0
- package/lib/Types/Product.js +3 -2
- package/lib/Types/Signal.js +3 -2
- package/lib/Types/Socket.js +4 -2
- package/lib/Types/State.js +11 -2
- package/lib/Types/USync.js +3 -2
- package/lib/Types/index.js +27 -41
- package/lib/Utils/auth-utils.js +211 -198
- package/lib/Utils/baileys-event-stream.js +42 -61
- package/lib/Utils/browser-utils.js +25 -0
- package/lib/Utils/business.js +213 -214
- package/lib/Utils/chat-utils.js +710 -687
- package/lib/Utils/crypto.js +112 -133
- package/lib/Utils/decode-wa-message.js +252 -183
- package/lib/Utils/decode-wa-message.js.bak +267 -0
- package/lib/Utils/event-buffer.js +510 -496
- package/lib/Utils/generics.js +319 -464
- package/lib/Utils/history.js +83 -92
- package/lib/Utils/index.js +21 -33
- package/lib/Utils/link-preview.js +71 -83
- package/lib/Utils/logger.js +5 -7
- package/lib/Utils/lt-hash.js +40 -46
- package/lib/Utils/make-mutex.js +34 -41
- package/lib/Utils/message-retry-manager.js +113 -0
- package/lib/Utils/messages-media.js +550 -768
- package/lib/Utils/messages.js +385 -261
- package/lib/Utils/noise-handler.js +138 -149
- package/lib/Utils/pre-key-manager.js +85 -0
- package/lib/Utils/process-message.js +323 -303
- package/lib/Utils/signal.js +149 -141
- package/lib/Utils/use-multi-file-auth-state.js +95 -103
- package/lib/Utils/validate-connection.js +183 -212
- package/lib/WABinary/constants.js +1298 -35
- package/lib/WABinary/decode.js +237 -249
- package/lib/WABinary/encode.js +213 -260
- package/lib/WABinary/generic-utils.js +56 -65
- package/lib/WABinary/index.js +7 -21
- package/lib/WABinary/jid-utils.js +89 -58
- package/lib/WABinary/types.js +3 -2
- package/lib/WAM/BinaryInfo.js +10 -12
- package/lib/WAM/constants.js +22851 -15348
- package/lib/WAM/encode.js +135 -136
- package/lib/WAM/index.js +5 -19
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +28 -30
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +49 -53
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +27 -28
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +36 -39
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +50 -50
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +26 -20
- package/lib/WAUSync/Protocols/index.js +6 -20
- package/lib/WAUSync/USyncQuery.js +86 -85
- package/lib/WAUSync/USyncUser.js +23 -25
- package/lib/WAUSync/index.js +5 -19
- package/lib/index.js +27 -36
- package/package.json +61 -85
- package/engine-requirements.js +0 -10
- package/lib/Defaults/baileys-version.json +0 -3
- package/lib/Defaults/index.d.ts +0 -53
- package/lib/Defaults/phonenumber-mcc.json +0 -223
- package/lib/Signal/Group/ciphertext-message.d.ts +0 -9
- package/lib/Signal/Group/group-session-builder.d.ts +0 -14
- package/lib/Signal/Group/group_cipher.d.ts +0 -17
- package/lib/Signal/Group/index.d.ts +0 -11
- package/lib/Signal/Group/keyhelper.d.ts +0 -10
- package/lib/Signal/Group/queue-job.d.ts +0 -1
- package/lib/Signal/Group/queue-job.js +0 -57
- package/lib/Signal/Group/sender-chain-key.d.ts +0 -13
- package/lib/Signal/Group/sender-key-distribution-message.d.ts +0 -16
- package/lib/Signal/Group/sender-key-message.d.ts +0 -18
- package/lib/Signal/Group/sender-key-name.d.ts +0 -17
- package/lib/Signal/Group/sender-key-record.d.ts +0 -30
- package/lib/Signal/Group/sender-key-state.d.ts +0 -38
- package/lib/Signal/Group/sender-message-key.d.ts +0 -11
- package/lib/Signal/libsignal.d.ts +0 -3
- package/lib/Socket/Client/abstract-socket-client.d.ts +0 -17
- package/lib/Socket/Client/abstract-socket-client.js +0 -13
- package/lib/Socket/Client/index.d.ts +0 -3
- package/lib/Socket/Client/mobile-socket-client.d.ts +0 -13
- package/lib/Socket/Client/mobile-socket-client.js +0 -65
- package/lib/Socket/Client/web-socket-client.d.ts +0 -12
- package/lib/Socket/Client/web-socket-client.js +0 -62
- package/lib/Socket/business.d.ts +0 -171
- package/lib/Socket/chats.d.ts +0 -267
- package/lib/Socket/dugong.d.ts +0 -254
- package/lib/Socket/dugong.js +0 -484
- package/lib/Socket/groups.d.ts +0 -115
- package/lib/Socket/index.d.ts +0 -173
- package/lib/Socket/messages-recv.d.ts +0 -161
- package/lib/Socket/messages-send.d.ts +0 -149
- package/lib/Socket/newsletter.d.ts +0 -134
- package/lib/Socket/registration.d.ts +0 -267
- package/lib/Socket/registration.js +0 -166
- package/lib/Socket/socket.d.ts +0 -43
- package/lib/Socket/usync.d.ts +0 -36
- package/lib/Socket/usync.js +0 -70
- package/lib/Store/index.d.ts +0 -3
- package/lib/Store/make-cache-manager-store.d.ts +0 -13
- package/lib/Store/make-in-memory-store.d.ts +0 -118
- package/lib/Store/make-ordered-dictionary.d.ts +0 -13
- package/lib/Store/object-repository.d.ts +0 -10
- package/lib/Types/Auth.d.ts +0 -110
- package/lib/Types/Call.d.ts +0 -13
- package/lib/Types/Chat.d.ts +0 -102
- package/lib/Types/Contact.d.ts +0 -19
- package/lib/Types/Events.d.ts +0 -157
- package/lib/Types/GroupMetadata.d.ts +0 -55
- package/lib/Types/Label.d.ts +0 -35
- package/lib/Types/LabelAssociation.d.ts +0 -29
- package/lib/Types/Message.d.ts +0 -273
- package/lib/Types/Newsletter.d.ts +0 -103
- package/lib/Types/Product.d.ts +0 -78
- package/lib/Types/Signal.d.ts +0 -57
- package/lib/Types/Socket.d.ts +0 -111
- package/lib/Types/State.d.ts +0 -27
- package/lib/Types/USync.d.ts +0 -25
- package/lib/Types/index.d.ts +0 -57
- package/lib/Utils/auth-utils.d.ts +0 -18
- package/lib/Utils/baileys-event-stream.d.ts +0 -16
- package/lib/Utils/business.d.ts +0 -22
- package/lib/Utils/chat-utils.d.ts +0 -71
- package/lib/Utils/crypto.d.ts +0 -41
- package/lib/Utils/decode-wa-message.d.ts +0 -19
- package/lib/Utils/event-buffer.d.ts +0 -35
- package/lib/Utils/generics.d.ts +0 -92
- package/lib/Utils/history.d.ts +0 -15
- package/lib/Utils/index.d.ts +0 -17
- package/lib/Utils/link-preview.d.ts +0 -21
- package/lib/Utils/logger.d.ts +0 -4
- package/lib/Utils/lt-hash.d.ts +0 -12
- package/lib/Utils/make-mutex.d.ts +0 -7
- package/lib/Utils/messages-media.d.ts +0 -116
- package/lib/Utils/messages.d.ts +0 -77
- package/lib/Utils/noise-handler.d.ts +0 -21
- package/lib/Utils/process-message.d.ts +0 -41
- package/lib/Utils/signal.d.ts +0 -32
- package/lib/Utils/use-multi-file-auth-state.d.ts +0 -13
- package/lib/Utils/validate-connection.d.ts +0 -11
- package/lib/WABinary/constants.d.ts +0 -30
- package/lib/WABinary/decode.d.ts +0 -7
- package/lib/WABinary/encode.d.ts +0 -3
- package/lib/WABinary/generic-utils.d.ts +0 -17
- package/lib/WABinary/index.d.ts +0 -5
- package/lib/WABinary/jid-utils.d.ts +0 -31
- package/lib/WABinary/types.d.ts +0 -18
- package/lib/WAM/BinaryInfo.d.ts +0 -17
- package/lib/WAM/constants.d.ts +0 -38
- package/lib/WAM/encode.d.ts +0 -3
- package/lib/WAM/index.d.ts +0 -3
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -9
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -22
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -12
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -12
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.d.ts +0 -25
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.d.ts +0 -8
- package/lib/WAUSync/Protocols/index.d.ts +0 -4
- package/lib/WAUSync/USyncQuery.d.ts +0 -28
- package/lib/WAUSync/USyncUser.d.ts +0 -12
- package/lib/WAUSync/index.d.ts +0 -3
- package/lib/index.d.ts +0 -12
|
@@ -1,68 +1,89 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
1
|
+
import NodeCache from '@cacheable/node-cache';
|
|
2
|
+
import { Boom } from '@hapi/boom';
|
|
3
|
+
import { proto } from '../../WAProto/index.js';
|
|
4
|
+
import {
|
|
5
|
+
DEFAULT_CACHE_TTLS,
|
|
6
|
+
WA_DEFAULT_EPHEMERAL
|
|
7
|
+
} from '../Defaults/index.js';
|
|
8
|
+
import {
|
|
9
|
+
aggregateMessageKeysNotFromMe,
|
|
10
|
+
assertMediaContent,
|
|
11
|
+
bindWaitForEvent,
|
|
12
|
+
decryptMediaRetryData,
|
|
13
|
+
encodeNewsletterMessage,
|
|
14
|
+
encodeSignedDeviceIdentity,
|
|
15
|
+
encodeWAMessage,
|
|
16
|
+
encryptMediaRetryRequest,
|
|
17
|
+
extractDeviceJids,
|
|
18
|
+
generateMessageIDV2,
|
|
19
|
+
generateParticipantHashV2,
|
|
20
|
+
generateWAMessage,
|
|
21
|
+
getStatusCodeForMediaRetry,
|
|
22
|
+
getUrlFromDirectPath,
|
|
23
|
+
getWAUploadToServer,
|
|
24
|
+
MessageRetryManager,
|
|
25
|
+
normalizeMessageContent,
|
|
26
|
+
parseAndInjectE2ESessions,
|
|
27
|
+
unixTimestampSeconds
|
|
28
|
+
} from '../Utils/index.js';
|
|
29
|
+
import {
|
|
30
|
+
areJidsSameUser,
|
|
31
|
+
getBinaryNodeChild,
|
|
32
|
+
getBinaryNodeChildren,
|
|
33
|
+
getAdditionalNode,
|
|
34
|
+
getBinaryNodeFilter,
|
|
35
|
+
isHostedLidUser,
|
|
36
|
+
isHostedPnUser,
|
|
37
|
+
isJidGroup,
|
|
38
|
+
isLidUser,
|
|
39
|
+
isPnUser,
|
|
40
|
+
jidDecode,
|
|
41
|
+
jidEncode,
|
|
42
|
+
isJidNewsletter,
|
|
43
|
+
jidNormalizedUser,
|
|
44
|
+
S_WHATSAPP_NET
|
|
45
|
+
} from '../WABinary/index.js';
|
|
46
|
+
import { getUrlInfo } from '../Utils/link-preview.js';
|
|
47
|
+
import { makeKeyedMutex } from '../Utils/make-mutex.js';
|
|
48
|
+
import { USyncQuery, USyncUser } from '../WAUSync/index.js';
|
|
49
|
+
import { makeNewsletterSocket } from './newsletter.js';
|
|
50
|
+
export const makeMessagesSocket = (config) => {
|
|
51
|
+
const { logger, linkPreviewImageThumbnailWidth, generateHighQualityLinkPreview, options: httpRequestOptions, patchMessageBeforeSending, cachedGroupMetadata, enableRecentMessageCache, maxMsgRetryCount } = config;
|
|
52
|
+
const sock = makeNewsletterSocket(config);
|
|
53
|
+
const { ev, authState, processingMutex, signalRepository, upsertMessage, query, fetchPrivacySettings, sendNode, groupMetadata, groupToggleEphemeral } = sock;
|
|
54
|
+
const userDevicesCache = config.userDevicesCache ||
|
|
55
|
+
new NodeCache({
|
|
56
|
+
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES, // 5 minutes
|
|
57
|
+
useClones: false
|
|
58
|
+
});
|
|
59
|
+
const peerSessionsCache = new NodeCache({
|
|
60
|
+
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
|
|
45
61
|
useClones: false
|
|
46
62
|
});
|
|
63
|
+
// Initialize message retry manager if enabled
|
|
64
|
+
const messageRetryManager = enableRecentMessageCache ? new MessageRetryManager(logger, maxMsgRetryCount) : null;
|
|
65
|
+
// Prevent race conditions in Signal session encryption by user
|
|
66
|
+
const encryptionMutex = makeKeyedMutex();
|
|
47
67
|
let mediaConn;
|
|
48
68
|
const refreshMediaConn = async (forceGet = false) => {
|
|
49
69
|
const media = await mediaConn;
|
|
50
|
-
if (!media || forceGet ||
|
|
70
|
+
if (!media || forceGet || new Date().getTime() - media.fetchDate.getTime() > media.ttl * 1000) {
|
|
51
71
|
mediaConn = (async () => {
|
|
52
72
|
const result = await query({
|
|
53
73
|
tag: 'iq',
|
|
54
74
|
attrs: {
|
|
55
75
|
type: 'set',
|
|
56
76
|
xmlns: 'w:m',
|
|
57
|
-
to:
|
|
77
|
+
to: S_WHATSAPP_NET
|
|
58
78
|
},
|
|
59
79
|
content: [{ tag: 'media_conn', attrs: {} }]
|
|
60
80
|
});
|
|
61
|
-
const mediaConnNode =
|
|
81
|
+
const mediaConnNode = getBinaryNodeChild(result, 'media_conn');
|
|
82
|
+
// TODO: explore full length of data that whatsapp provides
|
|
62
83
|
const node = {
|
|
63
|
-
hosts:
|
|
84
|
+
hosts: getBinaryNodeChildren(mediaConnNode, 'host').map(({ attrs }) => ({
|
|
64
85
|
hostname: attrs.hostname,
|
|
65
|
-
maxContentLengthBytes: +attrs.maxContentLengthBytes
|
|
86
|
+
maxContentLengthBytes: +attrs.maxContentLengthBytes
|
|
66
87
|
})),
|
|
67
88
|
auth: mediaConnNode.attrs.auth,
|
|
68
89
|
ttl: +mediaConnNode.attrs.ttl,
|
|
@@ -79,17 +100,20 @@ const makeMessagesSocket = (config) => {
|
|
|
79
100
|
* used for receipts of phone call, read, delivery etc.
|
|
80
101
|
* */
|
|
81
102
|
const sendReceipt = async (jid, participant, messageIds, type) => {
|
|
103
|
+
if (!messageIds || messageIds.length === 0) {
|
|
104
|
+
throw new Boom('missing ids in receipt');
|
|
105
|
+
}
|
|
82
106
|
const node = {
|
|
83
107
|
tag: 'receipt',
|
|
84
108
|
attrs: {
|
|
85
|
-
id: messageIds[0]
|
|
86
|
-
}
|
|
109
|
+
id: messageIds[0]
|
|
110
|
+
}
|
|
87
111
|
};
|
|
88
112
|
const isReadReceipt = type === 'read' || type === 'read-self';
|
|
89
113
|
if (isReadReceipt) {
|
|
90
|
-
node.attrs.t =
|
|
114
|
+
node.attrs.t = unixTimestampSeconds().toString();
|
|
91
115
|
}
|
|
92
|
-
if (type === 'sender' &&
|
|
116
|
+
if (type === 'sender' && (isPnUser(jid) || isLidUser(jid))) {
|
|
93
117
|
node.attrs.recipient = jid;
|
|
94
118
|
node.attrs.to = participant;
|
|
95
119
|
}
|
|
@@ -100,7 +124,7 @@ const makeMessagesSocket = (config) => {
|
|
|
100
124
|
}
|
|
101
125
|
}
|
|
102
126
|
if (type) {
|
|
103
|
-
node.attrs.type =
|
|
127
|
+
node.attrs.type = type;
|
|
104
128
|
}
|
|
105
129
|
const remainingMessageIds = messageIds.slice(1);
|
|
106
130
|
if (remainingMessageIds.length) {
|
|
@@ -120,7 +144,7 @@ const makeMessagesSocket = (config) => {
|
|
|
120
144
|
};
|
|
121
145
|
/** Correctly bulk send receipts to multiple chats, participants */
|
|
122
146
|
const sendReceipts = async (keys, type) => {
|
|
123
|
-
const recps =
|
|
147
|
+
const recps = aggregateMessageKeysNotFromMe(keys);
|
|
124
148
|
for (const { jid, participant, messageIds } of recps) {
|
|
125
149
|
await sendReceipt(jid, participant, messageIds, type);
|
|
126
150
|
}
|
|
@@ -134,207 +158,349 @@ const makeMessagesSocket = (config) => {
|
|
|
134
158
|
};
|
|
135
159
|
/** Fetch all the devices we've to send a message to */
|
|
136
160
|
const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
|
|
137
|
-
const deviceResults = []
|
|
138
|
-
|
|
161
|
+
const deviceResults = [];
|
|
139
162
|
if (!useCache) {
|
|
140
|
-
logger.debug('not using cache for devices')
|
|
163
|
+
logger.debug('not using cache for devices');
|
|
141
164
|
}
|
|
142
|
-
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
165
|
+
const toFetch = [];
|
|
166
|
+
const jidsWithUser = jids
|
|
167
|
+
.map(jid => {
|
|
168
|
+
const decoded = jidDecode(jid);
|
|
169
|
+
const user = decoded?.user;
|
|
170
|
+
const device = decoded?.device;
|
|
171
|
+
const isExplicitDevice = typeof device === 'number' && device >= 0;
|
|
172
|
+
if (isExplicitDevice && user) {
|
|
173
|
+
deviceResults.push({
|
|
174
|
+
user,
|
|
175
|
+
device,
|
|
176
|
+
jid
|
|
177
|
+
});
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
jid = jidNormalizedUser(jid);
|
|
181
|
+
return { jid, user };
|
|
182
|
+
})
|
|
183
|
+
.filter(jid => jid !== null);
|
|
184
|
+
let mgetDevices;
|
|
185
|
+
if (useCache && userDevicesCache.mget) {
|
|
186
|
+
const usersToFetch = jidsWithUser.map(j => j?.user).filter(Boolean);
|
|
187
|
+
mgetDevices = await userDevicesCache.mget(usersToFetch);
|
|
188
|
+
}
|
|
189
|
+
for (const { jid, user } of jidsWithUser) {
|
|
152
190
|
if (useCache) {
|
|
153
|
-
const devices =
|
|
154
|
-
|
|
191
|
+
const devices = mgetDevices?.[user] ||
|
|
192
|
+
(userDevicesCache.mget ? undefined : (await userDevicesCache.get(user)));
|
|
155
193
|
if (devices) {
|
|
156
|
-
|
|
157
|
-
|
|
194
|
+
const devicesWithJid = devices.map(d => ({
|
|
195
|
+
...d,
|
|
196
|
+
jid: jidEncode(d.user, d.server, d.device)
|
|
197
|
+
}));
|
|
198
|
+
deviceResults.push(...devicesWithJid);
|
|
199
|
+
logger.trace({ user }, 'using cache for devices');
|
|
158
200
|
}
|
|
159
|
-
|
|
160
201
|
else {
|
|
161
|
-
toFetch.push(jid)
|
|
202
|
+
toFetch.push(jid);
|
|
162
203
|
}
|
|
163
204
|
}
|
|
164
|
-
|
|
165
205
|
else {
|
|
166
|
-
toFetch.push(jid)
|
|
206
|
+
toFetch.push(jid);
|
|
167
207
|
}
|
|
168
208
|
}
|
|
169
|
-
|
|
170
209
|
if (!toFetch.length) {
|
|
171
|
-
return deviceResults
|
|
210
|
+
return deviceResults;
|
|
172
211
|
}
|
|
173
|
-
|
|
174
|
-
const query = new WAUSync_1.USyncQuery()
|
|
175
|
-
.withContext('message')
|
|
176
|
-
.withDeviceProtocol()
|
|
177
|
-
|
|
212
|
+
const requestedLidUsers = new Set();
|
|
178
213
|
for (const jid of toFetch) {
|
|
179
|
-
|
|
214
|
+
if (isLidUser(jid) || isHostedLidUser(jid)) {
|
|
215
|
+
const user = jidDecode(jid)?.user;
|
|
216
|
+
if (user)
|
|
217
|
+
requestedLidUsers.add(user);
|
|
218
|
+
}
|
|
180
219
|
}
|
|
181
|
-
|
|
182
|
-
const
|
|
183
|
-
|
|
220
|
+
const query = new USyncQuery().withContext('message').withDeviceProtocol().withLIDProtocol();
|
|
221
|
+
for (const jid of toFetch) {
|
|
222
|
+
query.withUser(new USyncUser().withId(jid)); // todo: investigate - the idea here is that <user> should have an inline lid field with the lid being the pn equivalent
|
|
223
|
+
}
|
|
224
|
+
const result = await sock.executeUSyncQuery(query);
|
|
184
225
|
if (result) {
|
|
185
|
-
|
|
186
|
-
const
|
|
187
|
-
|
|
226
|
+
// TODO: LID MAP this stuff (lid protocol will now return lid with devices)
|
|
227
|
+
const lidResults = result.list.filter(a => !!a.lid);
|
|
228
|
+
if (lidResults.length > 0) {
|
|
229
|
+
logger.trace('Storing LID maps from device call');
|
|
230
|
+
await signalRepository.lidMapping.storeLIDPNMappings(lidResults.map(a => ({ lid: a.lid, pn: a.id })));
|
|
231
|
+
}
|
|
232
|
+
const extracted = extractDeviceJids(result?.list, authState.creds.me.id, authState.creds.me.lid, ignoreZeroDevices);
|
|
233
|
+
const deviceMap = {};
|
|
188
234
|
for (const item of extracted) {
|
|
189
|
-
deviceMap[item.user] = deviceMap[item.user] || []
|
|
190
|
-
deviceMap[item.user]
|
|
191
|
-
deviceResults.push(item)
|
|
235
|
+
deviceMap[item.user] = deviceMap[item.user] || [];
|
|
236
|
+
deviceMap[item.user]?.push(item);
|
|
192
237
|
}
|
|
193
|
-
|
|
194
|
-
for (const
|
|
195
|
-
|
|
238
|
+
// Process each user's devices as a group for bulk LID migration
|
|
239
|
+
for (const [user, userDevices] of Object.entries(deviceMap)) {
|
|
240
|
+
const isLidUser = requestedLidUsers.has(user);
|
|
241
|
+
// Process all devices for this user
|
|
242
|
+
for (const item of userDevices) {
|
|
243
|
+
const finalJid = isLidUser
|
|
244
|
+
? jidEncode(user, item.server, item.device)
|
|
245
|
+
: jidEncode(item.user, item.server, item.device);
|
|
246
|
+
deviceResults.push({
|
|
247
|
+
...item,
|
|
248
|
+
jid: finalJid
|
|
249
|
+
});
|
|
250
|
+
logger.debug({
|
|
251
|
+
user: item.user,
|
|
252
|
+
device: item.device,
|
|
253
|
+
finalJid,
|
|
254
|
+
usedLid: isLidUser
|
|
255
|
+
}, 'Processed device with LID priority');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
if (userDevicesCache.mset) {
|
|
259
|
+
// if the cache supports mset, we can set all devices in one go
|
|
260
|
+
await userDevicesCache.mset(Object.entries(deviceMap).map(([key, value]) => ({ key, value })));
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
for (const key in deviceMap) {
|
|
264
|
+
if (deviceMap[key])
|
|
265
|
+
await userDevicesCache.set(key, deviceMap[key]);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const userDeviceUpdates = {};
|
|
269
|
+
for (const [userId, devices] of Object.entries(deviceMap)) {
|
|
270
|
+
if (devices && devices.length > 0) {
|
|
271
|
+
userDeviceUpdates[userId] = devices.map(d => d.device?.toString() || '0');
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (Object.keys(userDeviceUpdates).length > 0) {
|
|
275
|
+
try {
|
|
276
|
+
await authState.keys.set({ 'device-list': userDeviceUpdates });
|
|
277
|
+
logger.debug({ userCount: Object.keys(userDeviceUpdates).length }, 'stored user device lists for bulk migration');
|
|
278
|
+
}
|
|
279
|
+
catch (error) {
|
|
280
|
+
logger.warn({ error }, 'failed to store user device lists');
|
|
281
|
+
}
|
|
196
282
|
}
|
|
197
283
|
}
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const assertSessions = async (jids, force) => {
|
|
284
|
+
return deviceResults;
|
|
285
|
+
};
|
|
286
|
+
const assertSessions = async (jids) => {
|
|
202
287
|
let didFetchNewSession = false;
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
288
|
+
const uniqueJids = [...new Set(jids)]; // Deduplicate JIDs
|
|
289
|
+
const jidsRequiringFetch = [];
|
|
290
|
+
logger.debug({ jids }, 'assertSessions call with jids');
|
|
291
|
+
// Check peerSessionsCache and validate sessions using libsignal loadSession
|
|
292
|
+
for (const jid of uniqueJids) {
|
|
293
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(jid);
|
|
294
|
+
const cachedSession = peerSessionsCache.get(signalId);
|
|
295
|
+
if (cachedSession !== undefined) {
|
|
296
|
+
if (cachedSession) {
|
|
297
|
+
continue; // Session exists in cache
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
const sessionValidation = await signalRepository.validateSession(jid);
|
|
302
|
+
const hasSession = sessionValidation.exists;
|
|
303
|
+
peerSessionsCache.set(signalId, hasSession);
|
|
304
|
+
if (hasSession) {
|
|
305
|
+
continue;
|
|
216
306
|
}
|
|
217
307
|
}
|
|
308
|
+
jidsRequiringFetch.push(jid);
|
|
218
309
|
}
|
|
219
310
|
if (jidsRequiringFetch.length) {
|
|
220
|
-
|
|
311
|
+
// LID if mapped, otherwise original
|
|
312
|
+
const wireJids = [
|
|
313
|
+
...jidsRequiringFetch.filter(jid => !!isLidUser(jid) || !!isHostedLidUser(jid)),
|
|
314
|
+
...((await signalRepository.lidMapping.getLIDsForPNs(jidsRequiringFetch.filter(jid => !!isPnUser(jid) || !!isHostedPnUser(jid)))) || []).map(a => a.lid)
|
|
315
|
+
];
|
|
316
|
+
logger.debug({ jidsRequiringFetch, wireJids }, 'fetching sessions');
|
|
221
317
|
const result = await query({
|
|
222
318
|
tag: 'iq',
|
|
223
319
|
attrs: {
|
|
224
320
|
xmlns: 'encrypt',
|
|
225
321
|
type: 'get',
|
|
226
|
-
to:
|
|
322
|
+
to: S_WHATSAPP_NET
|
|
227
323
|
},
|
|
228
324
|
content: [
|
|
229
325
|
{
|
|
230
326
|
tag: 'key',
|
|
231
327
|
attrs: {},
|
|
232
|
-
content:
|
|
328
|
+
content: wireJids.map(jid => ({
|
|
233
329
|
tag: 'user',
|
|
234
|
-
attrs: { jid }
|
|
330
|
+
attrs: { jid }
|
|
235
331
|
}))
|
|
236
332
|
}
|
|
237
333
|
]
|
|
238
334
|
});
|
|
239
|
-
await
|
|
335
|
+
await parseAndInjectE2ESessions(result, signalRepository);
|
|
240
336
|
didFetchNewSession = true;
|
|
337
|
+
// Cache fetched sessions using wire JIDs
|
|
338
|
+
for (const wireJid of wireJids) {
|
|
339
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(wireJid);
|
|
340
|
+
peerSessionsCache.set(signalId, true);
|
|
341
|
+
}
|
|
241
342
|
}
|
|
242
343
|
return didFetchNewSession;
|
|
243
344
|
};
|
|
244
|
-
|
|
245
|
-
|
|
246
345
|
const sendPeerDataOperationMessage = async (pdoMessage) => {
|
|
346
|
+
//TODO: for later, abstract the logic to send a Peer Message instead of just PDO - useful for App State Key Resync with phone
|
|
247
347
|
if (!authState.creds.me?.id) {
|
|
248
|
-
throw new
|
|
348
|
+
throw new Boom('Not authenticated');
|
|
249
349
|
}
|
|
250
|
-
|
|
251
350
|
const protocolMessage = {
|
|
252
351
|
protocolMessage: {
|
|
253
352
|
peerDataOperationRequestMessage: pdoMessage,
|
|
254
|
-
type:
|
|
353
|
+
type: proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE
|
|
255
354
|
}
|
|
256
355
|
};
|
|
257
|
-
const meJid =
|
|
356
|
+
const meJid = jidNormalizedUser(authState.creds.me.id);
|
|
258
357
|
const msgId = await relayMessage(meJid, protocolMessage, {
|
|
259
358
|
additionalAttributes: {
|
|
260
359
|
category: 'peer',
|
|
261
|
-
|
|
262
|
-
push_priority: 'high_force',
|
|
360
|
+
push_priority: 'high_force'
|
|
263
361
|
},
|
|
362
|
+
additionalNodes: [
|
|
363
|
+
{
|
|
364
|
+
tag: 'meta',
|
|
365
|
+
attrs: { appdata: 'default' }
|
|
366
|
+
}
|
|
367
|
+
]
|
|
264
368
|
});
|
|
265
369
|
return msgId;
|
|
266
370
|
};
|
|
267
|
-
const createParticipantNodes = async (
|
|
268
|
-
|
|
269
|
-
|
|
371
|
+
const createParticipantNodes = async (recipientJids, message, extraAttrs, dsmMessage) => {
|
|
372
|
+
if (!recipientJids.length) {
|
|
373
|
+
return { nodes: [], shouldIncludeDeviceIdentity: false };
|
|
374
|
+
}
|
|
375
|
+
const patched = await patchMessageBeforeSending(message, recipientJids);
|
|
376
|
+
const patchedMessages = Array.isArray(patched)
|
|
377
|
+
? patched
|
|
378
|
+
: recipientJids.map(jid => ({ recipientJid: jid, message: patched }));
|
|
270
379
|
let shouldIncludeDeviceIdentity = false;
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
380
|
+
const meId = authState.creds.me.id;
|
|
381
|
+
const meLid = authState.creds.me?.lid;
|
|
382
|
+
const meLidUser = meLid ? jidDecode(meLid)?.user : null;
|
|
383
|
+
const encryptionPromises = patchedMessages.map(async ({ recipientJid: jid, message: patchedMessage }) => {
|
|
384
|
+
if (!jid)
|
|
385
|
+
return null;
|
|
386
|
+
let msgToEncrypt = patchedMessage;
|
|
387
|
+
if (dsmMessage) {
|
|
388
|
+
const { user: targetUser } = jidDecode(jid);
|
|
389
|
+
const { user: ownPnUser } = jidDecode(meId);
|
|
390
|
+
const ownLidUser = meLidUser;
|
|
391
|
+
const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser);
|
|
392
|
+
const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
|
|
393
|
+
if (isOwnUser && !isExactSenderDevice) {
|
|
394
|
+
msgToEncrypt = dsmMessage;
|
|
395
|
+
logger.debug({ jid, targetUser }, 'Using DSM for own device');
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
const bytes = encodeWAMessage(msgToEncrypt);
|
|
399
|
+
const mutexKey = jid;
|
|
400
|
+
const node = await encryptionMutex.mutex(mutexKey, async () => {
|
|
401
|
+
const { type, ciphertext } = await signalRepository.encryptMessage({
|
|
402
|
+
jid,
|
|
403
|
+
data: bytes
|
|
404
|
+
});
|
|
405
|
+
if (type === 'pkmsg') {
|
|
406
|
+
shouldIncludeDeviceIdentity = true;
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
tag: 'to',
|
|
410
|
+
attrs: { jid },
|
|
411
|
+
content: [
|
|
412
|
+
{
|
|
413
|
+
tag: 'enc',
|
|
414
|
+
attrs: {
|
|
415
|
+
v: '2',
|
|
416
|
+
type,
|
|
417
|
+
...(extraAttrs || {})
|
|
418
|
+
},
|
|
419
|
+
content: ciphertext
|
|
420
|
+
}
|
|
421
|
+
]
|
|
422
|
+
};
|
|
423
|
+
});
|
|
290
424
|
return node;
|
|
291
|
-
})
|
|
425
|
+
});
|
|
426
|
+
const nodes = (await Promise.all(encryptionPromises)).filter(node => node !== null);
|
|
292
427
|
return { nodes, shouldIncludeDeviceIdentity };
|
|
293
|
-
};
|
|
294
|
-
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache,
|
|
295
|
-
|
|
296
|
-
let shouldIncludeDeviceIdentity = false;
|
|
428
|
+
};
|
|
429
|
+
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, additionalNodes, useUserDevicesCache, useCachedGroupMetadata, statusJidList, AI = false }) => {
|
|
430
|
+
// let shouldIncludeDeviceIdentity = false;
|
|
297
431
|
let didPushAdditional = false
|
|
298
|
-
const
|
|
432
|
+
const meId = authState.creds.me.id;
|
|
433
|
+
const meLid = authState.creds.me?.lid;
|
|
434
|
+
const isRetryResend = Boolean(participant?.jid);
|
|
435
|
+
let shouldIncludeDeviceIdentity = isRetryResend;
|
|
299
436
|
const statusJid = 'status@broadcast';
|
|
437
|
+
const { user, server } = jidDecode(jid);
|
|
300
438
|
const isGroup = server === 'g.us';
|
|
301
439
|
const isStatus = jid === statusJid;
|
|
302
440
|
const isLid = server === 'lid';
|
|
303
|
-
const isPrivate = server === 's.whatsapp.net'
|
|
304
441
|
const isNewsletter = server === 'newsletter';
|
|
305
|
-
|
|
442
|
+
const isPrivate = server === 's.whatsapp.net'
|
|
443
|
+
const finalJid = jid;
|
|
444
|
+
msgId = msgId || generateMessageIDV2(meId);
|
|
306
445
|
useUserDevicesCache = useUserDevicesCache !== false;
|
|
307
|
-
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus
|
|
446
|
+
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus;
|
|
308
447
|
const participants = [];
|
|
309
|
-
const destinationJid =
|
|
448
|
+
const destinationJid = !isStatus ? finalJid : statusJid;
|
|
310
449
|
const binaryNodeContent = [];
|
|
311
450
|
const devices = [];
|
|
312
451
|
const meMsg = {
|
|
313
452
|
deviceSentMessage: {
|
|
314
453
|
destinationJid,
|
|
315
454
|
message
|
|
316
|
-
}
|
|
455
|
+
},
|
|
456
|
+
messageContextInfo: message.messageContextInfo
|
|
317
457
|
};
|
|
318
|
-
const extraAttrs = {}
|
|
319
|
-
const messages =
|
|
458
|
+
const extraAttrs = {};
|
|
459
|
+
const messages = normalizeMessageContent(message)
|
|
320
460
|
const buttonType = getButtonType(messages);
|
|
321
461
|
if (participant) {
|
|
322
|
-
// when the retry request is not for a group
|
|
323
|
-
// only send to the specific device that asked for a retry
|
|
324
|
-
// otherwise the message is sent out to every device that should be a recipient
|
|
325
462
|
if (!isGroup && !isStatus) {
|
|
326
|
-
additionalAttributes = {
|
|
463
|
+
additionalAttributes = {
|
|
464
|
+
...additionalAttributes,
|
|
465
|
+
device_fanout: 'false'
|
|
466
|
+
};
|
|
327
467
|
}
|
|
328
|
-
const { user, device } =
|
|
329
|
-
devices.push({
|
|
468
|
+
const { user, device } = jidDecode(participant.jid);
|
|
469
|
+
devices.push({
|
|
470
|
+
user,
|
|
471
|
+
device,
|
|
472
|
+
jid: participant.jid
|
|
473
|
+
});
|
|
330
474
|
}
|
|
331
475
|
await authState.keys.transaction(async () => {
|
|
332
|
-
const mediaType = getMediaType(
|
|
333
|
-
|
|
476
|
+
const mediaType = getMediaType(message);
|
|
334
477
|
if (mediaType) {
|
|
335
|
-
extraAttrs['mediatype'] = mediaType
|
|
478
|
+
extraAttrs['mediatype'] = mediaType;
|
|
336
479
|
}
|
|
337
480
|
|
|
481
|
+
if (isNewsletter) {
|
|
482
|
+
const patched = patchMessageBeforeSending ? await patchMessageBeforeSending(message, []) : message;
|
|
483
|
+
const bytes = encodeNewsletterMessage(patched);
|
|
484
|
+
binaryNodeContent.push({
|
|
485
|
+
tag: "plaintext",
|
|
486
|
+
attrs: mediaType ? { mediatype: mediaType } : {},
|
|
487
|
+
content: bytes
|
|
488
|
+
});
|
|
489
|
+
const stanza = {
|
|
490
|
+
tag: "message",
|
|
491
|
+
attrs: {
|
|
492
|
+
to: jid,
|
|
493
|
+
id: msgId,
|
|
494
|
+
type: getTypeMessage(message),
|
|
495
|
+
...(additionalAttributes || {})
|
|
496
|
+
},
|
|
497
|
+
content: binaryNodeContent
|
|
498
|
+
};
|
|
499
|
+
logger.debug({ msgId }, `sending newsletter message to ${jid}`);
|
|
500
|
+
await sendNode(stanza);
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
|
|
338
504
|
if (messages.pinInChatMessage || messages.keepInChatMessage || message.reactionMessage || message.protocolMessage?.editedMessage) {
|
|
339
505
|
extraAttrs['decrypt-fail'] = 'hide'
|
|
340
506
|
}
|
|
@@ -346,185 +512,228 @@ const makeMessagesSocket = (config) => {
|
|
|
346
512
|
if (isGroup || isStatus) {
|
|
347
513
|
const [groupData, senderKeyMap] = await Promise.all([
|
|
348
514
|
(async () => {
|
|
349
|
-
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined
|
|
350
|
-
if (groupData) {
|
|
351
|
-
logger.trace({
|
|
515
|
+
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined; // todo: should we rely on the cache specially if the cache is outdated and the metadata has new fields?
|
|
516
|
+
if (groupData && Array.isArray(groupData?.participants)) {
|
|
517
|
+
logger.trace({
|
|
518
|
+
jid,
|
|
519
|
+
participants: groupData.participants.length
|
|
520
|
+
}, 'using cached group metadata');
|
|
352
521
|
}
|
|
353
|
-
|
|
354
522
|
else if (!isStatus) {
|
|
355
|
-
groupData = await groupMetadata(jid)
|
|
523
|
+
groupData = await groupMetadata(jid); // TODO: start storing group participant list + addr mode in Signal & stop relying on this
|
|
356
524
|
}
|
|
357
|
-
|
|
358
525
|
return groupData;
|
|
359
526
|
})(),
|
|
360
527
|
(async () => {
|
|
361
528
|
if (!participant && !isStatus) {
|
|
362
|
-
|
|
363
|
-
|
|
529
|
+
// what if sender memory is less accurate than the cached metadata
|
|
530
|
+
// on participant change in group, we should do sender memory manipulation
|
|
531
|
+
const result = await authState.keys.get('sender-key-memory', [jid]); // TODO: check out what if the sender key memory doesn't include the LID stuff now?
|
|
532
|
+
return result[jid] || {};
|
|
364
533
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
})()
|
|
534
|
+
return {};
|
|
535
|
+
})()
|
|
369
536
|
]);
|
|
370
537
|
if (!participant) {
|
|
371
|
-
const participantsList =
|
|
372
|
-
|
|
538
|
+
const participantsList = groupData && !isStatus ? groupData.participants.map(p => p.id) : [];
|
|
373
539
|
if (isStatus && statusJidList) {
|
|
374
|
-
participantsList.push(...statusJidList)
|
|
540
|
+
participantsList.push(...statusJidList);
|
|
375
541
|
}
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
// }
|
|
385
|
-
|
|
386
|
-
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false)
|
|
387
|
-
devices.push(...additionalDevices)
|
|
542
|
+
// if (!isStatus) {
|
|
543
|
+
// additionalAttributes = {
|
|
544
|
+
// ...additionalAttributes,
|
|
545
|
+
// addressing_mode: groupData?.addressingMode || 'pn'
|
|
546
|
+
// };
|
|
547
|
+
// }
|
|
548
|
+
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false);
|
|
549
|
+
devices.push(...additionalDevices);
|
|
388
550
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
551
|
+
if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
|
|
552
|
+
additionalAttributes = {
|
|
553
|
+
...additionalAttributes,
|
|
554
|
+
expiration: groupData.ephemeralDuration.toString()
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
const patched = await patchMessageBeforeSending(message);
|
|
558
|
+
if (Array.isArray(patched)) {
|
|
559
|
+
throw new Boom('Per-jid patching is not supported in groups');
|
|
560
|
+
}
|
|
561
|
+
const bytes = encodeWAMessage(patched);
|
|
562
|
+
const groupAddressingMode = additionalAttributes?.['addressing_mode'] || groupData?.addressingMode || 'lid';
|
|
563
|
+
const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId;
|
|
393
564
|
const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
|
|
394
565
|
group: destinationJid,
|
|
395
566
|
data: bytes,
|
|
396
|
-
meId
|
|
567
|
+
meId: groupSenderIdentity
|
|
397
568
|
});
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
const
|
|
402
|
-
if (!
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
569
|
+
const senderKeyRecipients = [];
|
|
570
|
+
for (const device of devices) {
|
|
571
|
+
const deviceJid = device.jid;
|
|
572
|
+
const hasKey = !!senderKeyMap[deviceJid];
|
|
573
|
+
if ((!hasKey || !!participant) &&
|
|
574
|
+
!isHostedLidUser(deviceJid) &&
|
|
575
|
+
!isHostedPnUser(deviceJid) &&
|
|
576
|
+
device.device !== 99) {
|
|
577
|
+
//todo: revamp all this logic
|
|
578
|
+
// the goal is to follow with what I said above for each group, and instead of a true false map of ids, we can set an array full of those the app has already sent pkmsgs
|
|
579
|
+
senderKeyRecipients.push(deviceJid);
|
|
580
|
+
senderKeyMap[deviceJid] = true;
|
|
406
581
|
}
|
|
407
582
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
if (senderKeyJids.length) {
|
|
411
|
-
logger.debug({ senderKeyJids }, 'sending new sender key');
|
|
583
|
+
if (senderKeyRecipients.length) {
|
|
584
|
+
logger.debug({ senderKeyJids: senderKeyRecipients }, 'sending new sender key');
|
|
412
585
|
const senderKeyMsg = {
|
|
413
586
|
senderKeyDistributionMessage: {
|
|
414
587
|
axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
|
|
415
588
|
groupId: destinationJid
|
|
416
589
|
}
|
|
417
590
|
};
|
|
418
|
-
|
|
419
|
-
|
|
591
|
+
const senderKeySessionTargets = senderKeyRecipients;
|
|
592
|
+
await assertSessions(senderKeySessionTargets);
|
|
593
|
+
const result = await createParticipantNodes(senderKeyRecipients, senderKeyMsg, extraAttrs);
|
|
420
594
|
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity;
|
|
421
595
|
participants.push(...result.nodes);
|
|
422
596
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
597
|
+
if (isRetryResend) {
|
|
598
|
+
const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
|
|
599
|
+
data: bytes,
|
|
600
|
+
jid: participant?.jid
|
|
601
|
+
});
|
|
602
|
+
binaryNodeContent.push({
|
|
603
|
+
tag: 'enc',
|
|
604
|
+
attrs: {
|
|
605
|
+
v: '2',
|
|
606
|
+
type,
|
|
607
|
+
count: participant.count.toString()
|
|
608
|
+
},
|
|
609
|
+
content: encryptedContent
|
|
610
|
+
});
|
|
435
611
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
612
|
+
else {
|
|
613
|
+
binaryNodeContent.push({
|
|
614
|
+
tag: 'enc',
|
|
615
|
+
attrs: {
|
|
616
|
+
v: '2',
|
|
617
|
+
type: 'skmsg',
|
|
618
|
+
...extraAttrs
|
|
619
|
+
},
|
|
620
|
+
content: ciphertext
|
|
621
|
+
});
|
|
622
|
+
await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } });
|
|
441
623
|
}
|
|
442
|
-
|
|
443
|
-
const patched = await patchMessageBeforeSending(message, [])
|
|
444
|
-
const bytes = Utils_1.encodeNewsletterMessage(patched)
|
|
445
|
-
|
|
446
|
-
binaryNodeContent.push({
|
|
447
|
-
tag: 'plaintext',
|
|
448
|
-
attrs: extraAttrs ? extraAttrs : {},
|
|
449
|
-
content: bytes
|
|
450
|
-
})
|
|
451
624
|
}
|
|
452
625
|
else {
|
|
453
|
-
|
|
626
|
+
// ADDRESSING CONSISTENCY: Match own identity to conversation context
|
|
627
|
+
// TODO: investigate if this is true
|
|
628
|
+
let ownId = meId;
|
|
629
|
+
if (isLid && meLid) {
|
|
630
|
+
ownId = meLid;
|
|
631
|
+
logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation');
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation');
|
|
635
|
+
}
|
|
636
|
+
const { user: ownUser } = jidDecode(ownId);
|
|
454
637
|
if (!participant) {
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
638
|
+
const targetUserServer = isLid ? 'lid' : 's.whatsapp.net';
|
|
639
|
+
devices.push({
|
|
640
|
+
user,
|
|
641
|
+
device: 0,
|
|
642
|
+
jid: jidEncode(user, targetUserServer, 0) // rajeh, todo: this entire logic is convoluted and weird.
|
|
643
|
+
});
|
|
644
|
+
if (user !== ownUser) {
|
|
645
|
+
const ownUserServer = isLid ? 'lid' : 's.whatsapp.net';
|
|
646
|
+
const ownUserForAddressing = isLid && meLid ? jidDecode(meLid).user : jidDecode(meId).user;
|
|
647
|
+
devices.push({
|
|
648
|
+
user: ownUserForAddressing,
|
|
649
|
+
device: 0,
|
|
650
|
+
jid: jidEncode(ownUserForAddressing, ownUserServer, 0)
|
|
651
|
+
});
|
|
458
652
|
}
|
|
459
|
-
|
|
460
653
|
if (additionalAttributes?.['category'] !== 'peer') {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
654
|
+
// Clear placeholders and enumerate actual devices
|
|
655
|
+
devices.length = 0;
|
|
656
|
+
// Use conversation-appropriate sender identity
|
|
657
|
+
const senderIdentity = isLid && meLid
|
|
658
|
+
? jidEncode(jidDecode(meLid)?.user, 'lid', undefined)
|
|
659
|
+
: jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined);
|
|
660
|
+
// Enumerate devices for sender and target with consistent addressing
|
|
661
|
+
const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false);
|
|
662
|
+
devices.push(...sessionDevices);
|
|
663
|
+
logger.debug({
|
|
664
|
+
deviceCount: devices.length,
|
|
665
|
+
devices: devices.map(d => `${d.user}:${d.device}@${jidDecode(d.jid)?.server}`)
|
|
666
|
+
}, 'Device enumeration complete with unified addressing');
|
|
464
667
|
}
|
|
465
668
|
}
|
|
466
|
-
const
|
|
467
|
-
const
|
|
468
|
-
const
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
669
|
+
const allRecipients = [];
|
|
670
|
+
const meRecipients = [];
|
|
671
|
+
const otherRecipients = [];
|
|
672
|
+
const { user: mePnUser } = jidDecode(meId);
|
|
673
|
+
const { user: meLidUser } = meLid ? jidDecode(meLid) : { user: null };
|
|
674
|
+
for (const { user, jid } of devices) {
|
|
675
|
+
const isExactSenderDevice = jid === meId || (meLid && jid === meLid);
|
|
676
|
+
if (isExactSenderDevice) {
|
|
677
|
+
logger.debug({ jid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)');
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
// Check if this is our device (could match either PN or LID user)
|
|
681
|
+
const isMe = user === mePnUser || user === meLidUser;
|
|
473
682
|
if (isMe) {
|
|
474
|
-
|
|
683
|
+
meRecipients.push(jid);
|
|
475
684
|
}
|
|
476
|
-
|
|
477
685
|
else {
|
|
478
|
-
|
|
686
|
+
otherRecipients.push(jid);
|
|
479
687
|
}
|
|
480
|
-
|
|
481
|
-
allJids.push(jid)
|
|
688
|
+
allRecipients.push(jid);
|
|
482
689
|
}
|
|
483
|
-
await assertSessions(
|
|
690
|
+
await assertSessions(allRecipients);
|
|
484
691
|
const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
|
|
485
|
-
|
|
486
|
-
createParticipantNodes(
|
|
487
|
-
|
|
692
|
+
// For own devices: use DSM if available (1:1 chats only)
|
|
693
|
+
createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
|
|
694
|
+
createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
|
|
695
|
+
]);
|
|
488
696
|
participants.push(...meNodes);
|
|
489
697
|
participants.push(...otherNodes);
|
|
698
|
+
/* if (meRecipients.length > 0 || otherRecipients.length > 0) {
|
|
699
|
+
extraAttrs['phash'] = generateParticipantHashV2([...meRecipients, ...otherRecipients]);
|
|
700
|
+
}*/
|
|
490
701
|
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2;
|
|
491
702
|
}
|
|
492
703
|
if (participants.length) {
|
|
493
704
|
if (additionalAttributes?.['category'] === 'peer') {
|
|
494
|
-
const peerNode = participants[0]?.content?.[0]
|
|
495
|
-
|
|
705
|
+
const peerNode = participants[0]?.content?.[0];
|
|
496
706
|
if (peerNode) {
|
|
497
|
-
binaryNodeContent.push(peerNode) // push only enc
|
|
707
|
+
binaryNodeContent.push(peerNode); // push only enc
|
|
498
708
|
}
|
|
499
709
|
}
|
|
500
|
-
|
|
501
710
|
else {
|
|
502
711
|
binaryNodeContent.push({
|
|
503
712
|
tag: 'participants',
|
|
504
713
|
attrs: {},
|
|
505
714
|
content: participants
|
|
506
|
-
})
|
|
715
|
+
});
|
|
507
716
|
}
|
|
508
717
|
}
|
|
509
|
-
|
|
510
718
|
const stanza = {
|
|
511
719
|
tag: 'message',
|
|
512
720
|
attrs: {
|
|
513
721
|
id: msgId,
|
|
514
|
-
|
|
722
|
+
to: destinationJid,
|
|
723
|
+
type: getTypeMessage(messages),
|
|
515
724
|
...(additionalAttributes || {})
|
|
516
725
|
},
|
|
517
726
|
content: binaryNodeContent
|
|
518
|
-
}
|
|
727
|
+
};
|
|
519
728
|
// if the participant to send to is explicitly specified (generally retry recp)
|
|
520
729
|
// ensure the message is only sent to that person
|
|
521
730
|
// if a retry receipt is sent to everyone -- it'll fail decryption for everyone else who received the msg
|
|
522
731
|
if (participant) {
|
|
523
|
-
if (
|
|
732
|
+
if (isJidGroup(destinationJid)) {
|
|
524
733
|
stanza.attrs.to = destinationJid;
|
|
525
734
|
stanza.attrs.participant = participant.jid;
|
|
526
735
|
}
|
|
527
|
-
else if (
|
|
736
|
+
else if (areJidsSameUser(participant.jid, meId)) {
|
|
528
737
|
stanza.attrs.to = participant.jid;
|
|
529
738
|
stanza.attrs.recipient = destinationJid;
|
|
530
739
|
}
|
|
@@ -536,14 +745,14 @@ const makeMessagesSocket = (config) => {
|
|
|
536
745
|
stanza.attrs.to = destinationJid;
|
|
537
746
|
}
|
|
538
747
|
if (shouldIncludeDeviceIdentity) {
|
|
748
|
+
;
|
|
539
749
|
stanza.content.push({
|
|
540
750
|
tag: 'device-identity',
|
|
541
751
|
attrs: {},
|
|
542
|
-
content:
|
|
752
|
+
content: encodeSignedDeviceIdentity(authState.creds.account, true)
|
|
543
753
|
});
|
|
544
754
|
logger.debug({ jid }, 'adding device identity');
|
|
545
755
|
}
|
|
546
|
-
|
|
547
756
|
if (AI && isPrivate) {
|
|
548
757
|
const botNode = {
|
|
549
758
|
tag: 'bot',
|
|
@@ -552,7 +761,7 @@ const makeMessagesSocket = (config) => {
|
|
|
552
761
|
}
|
|
553
762
|
}
|
|
554
763
|
|
|
555
|
-
const filteredBizBot =
|
|
764
|
+
const filteredBizBot = getBinaryNodeFilter(additionalNodes ? additionalNodes : [])
|
|
556
765
|
|
|
557
766
|
if (filteredBizBot) {
|
|
558
767
|
stanza.content.push(...additionalNodes)
|
|
@@ -564,9 +773,9 @@ const makeMessagesSocket = (config) => {
|
|
|
564
773
|
}
|
|
565
774
|
}
|
|
566
775
|
|
|
567
|
-
if(
|
|
568
|
-
const content =
|
|
569
|
-
const filteredNode =
|
|
776
|
+
if(buttonType && !isStatus) {
|
|
777
|
+
const content = getAdditionalNode(buttonType)
|
|
778
|
+
const filteredNode = getBinaryNodeFilter(additionalNodes)
|
|
570
779
|
|
|
571
780
|
if (filteredNode) {
|
|
572
781
|
didPushAdditional = true
|
|
@@ -581,42 +790,44 @@ const makeMessagesSocket = (config) => {
|
|
|
581
790
|
if (!didPushAdditional && additionalNodes && additionalNodes.length > 0) {
|
|
582
791
|
stanza.content.push(...additionalNodes);
|
|
583
792
|
}
|
|
584
|
-
|
|
585
793
|
logger.debug({ msgId }, `sending message to ${participants.length} devices`);
|
|
586
794
|
await sendNode(stanza);
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
remoteJid: jid,
|
|
594
|
-
fromMe: true,
|
|
595
|
-
id: msgId
|
|
596
|
-
},
|
|
597
|
-
message: message,
|
|
598
|
-
messageTimestamp: Utils_1.unixTimestampSeconds(new Date()),
|
|
599
|
-
messageStubParameters: [],
|
|
600
|
-
participant: WABinary_1.isJidGroup(jid) || WABinary_1.isJidStatusBroadcast(jid) ? meId : undefined,
|
|
601
|
-
status: Types_1.WAMessageStatus.PENDING
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
return Types_1.WAProto.WebMessageInfo.fromObject(messageJSON)
|
|
605
|
-
// return msgId;
|
|
795
|
+
// Add message to retry cache if enabled
|
|
796
|
+
if (messageRetryManager && !participant) {
|
|
797
|
+
messageRetryManager.addRecentMessage(destinationJid, msgId, message);
|
|
798
|
+
}
|
|
799
|
+
}, meId);
|
|
800
|
+
return msgId;
|
|
606
801
|
};
|
|
607
802
|
const getTypeMessage = (msg) => {
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
803
|
+
if (msg.viewOnceMessage) {
|
|
804
|
+
return getTypeMessage(msg.viewOnceMessage.message);
|
|
805
|
+
}
|
|
806
|
+
else if (msg.viewOnceMessageV2) {
|
|
807
|
+
return getTypeMessage(msg.viewOnceMessageV2.message);
|
|
808
|
+
}
|
|
809
|
+
else if (msg.viewOnceMessageV2Extension) {
|
|
810
|
+
return getTypeMessage(msg.viewOnceMessageV2Extension.message);
|
|
811
|
+
}
|
|
812
|
+
else if (msg.ephemeralMessage) {
|
|
813
|
+
return getTypeMessage(msg.ephemeralMessage.message);
|
|
814
|
+
}
|
|
815
|
+
else if (msg.documentWithCaptionMessage) {
|
|
816
|
+
return getTypeMessage(msg.documentWithCaptionMessage.message);
|
|
817
|
+
}
|
|
818
|
+
else if (msg.reactionMessage) {
|
|
819
|
+
return 'reaction';
|
|
820
|
+
}
|
|
821
|
+
else if (msg.pollCreationMessage || msg.pollCreationMessageV2 || msg.pollCreationMessageV3 || msg.pollUpdateMessage) {
|
|
822
|
+
return 'poll';
|
|
823
|
+
}
|
|
824
|
+
else if (getMediaType(msg)) {
|
|
825
|
+
return 'media';
|
|
826
|
+
}
|
|
615
827
|
else {
|
|
616
|
-
return 'text'
|
|
828
|
+
return 'text';
|
|
617
829
|
}
|
|
618
|
-
}
|
|
619
|
-
|
|
830
|
+
};
|
|
620
831
|
const getMediaType = (message) => {
|
|
621
832
|
if (message.imageMessage) {
|
|
622
833
|
return 'image'
|
|
@@ -666,8 +877,7 @@ const makeMessagesSocket = (config) => {
|
|
|
666
877
|
else if (/https:\/\/wa\.me\/p\/\d+\/\d+/.test(message.extendedTextMessage?.text)) {
|
|
667
878
|
return 'productlink'
|
|
668
879
|
}
|
|
669
|
-
}
|
|
670
|
-
|
|
880
|
+
}
|
|
671
881
|
const getButtonType = (message) => {
|
|
672
882
|
if (message.listMessage) {
|
|
673
883
|
return 'list'
|
|
@@ -698,11 +908,11 @@ const makeMessagesSocket = (config) => {
|
|
|
698
908
|
}
|
|
699
909
|
}
|
|
700
910
|
const getPrivacyTokens = async (jids) => {
|
|
701
|
-
const t =
|
|
911
|
+
const t = unixTimestampSeconds().toString();
|
|
702
912
|
const result = await query({
|
|
703
913
|
tag: 'iq',
|
|
704
914
|
attrs: {
|
|
705
|
-
to:
|
|
915
|
+
to: S_WHATSAPP_NET,
|
|
706
916
|
type: 'set',
|
|
707
917
|
xmlns: 'privacy'
|
|
708
918
|
},
|
|
@@ -713,7 +923,7 @@ const makeMessagesSocket = (config) => {
|
|
|
713
923
|
content: jids.map(jid => ({
|
|
714
924
|
tag: 'token',
|
|
715
925
|
attrs: {
|
|
716
|
-
jid:
|
|
926
|
+
jid: jidNormalizedUser(jid),
|
|
717
927
|
t,
|
|
718
928
|
type: 'trusted_contact'
|
|
719
929
|
}
|
|
@@ -722,10 +932,9 @@ const makeMessagesSocket = (config) => {
|
|
|
722
932
|
]
|
|
723
933
|
});
|
|
724
934
|
return result;
|
|
725
|
-
}
|
|
726
|
-
const waUploadToServer =
|
|
727
|
-
const
|
|
728
|
-
const waitForMsgMediaUpdate = (0, Utils_1.bindWaitForEvent)(ev, 'messages.media-update');
|
|
935
|
+
};
|
|
936
|
+
const waUploadToServer = getWAUploadToServer(config, refreshMediaConn);
|
|
937
|
+
const waitForMsgMediaUpdate = bindWaitForEvent(ev, 'messages.media-update');
|
|
729
938
|
return {
|
|
730
939
|
...sock,
|
|
731
940
|
getPrivacyTokens,
|
|
@@ -733,23 +942,23 @@ const makeMessagesSocket = (config) => {
|
|
|
733
942
|
relayMessage,
|
|
734
943
|
sendReceipt,
|
|
735
944
|
sendReceipts,
|
|
736
|
-
rahmi,
|
|
737
945
|
readMessages,
|
|
738
946
|
refreshMediaConn,
|
|
739
|
-
getUSyncDevices,
|
|
740
|
-
createParticipantNodes,
|
|
741
947
|
waUploadToServer,
|
|
742
|
-
sendPeerDataOperationMessage,
|
|
743
948
|
fetchPrivacySettings,
|
|
949
|
+
sendPeerDataOperationMessage,
|
|
950
|
+
createParticipantNodes,
|
|
951
|
+
getUSyncDevices,
|
|
952
|
+
messageRetryManager,
|
|
744
953
|
updateMediaMessage: async (message) => {
|
|
745
|
-
const content =
|
|
954
|
+
const content = assertMediaContent(message.message);
|
|
746
955
|
const mediaKey = content.mediaKey;
|
|
747
956
|
const meId = authState.creds.me.id;
|
|
748
|
-
const node =
|
|
957
|
+
const node = await encryptMediaRetryRequest(message.key, mediaKey, meId);
|
|
749
958
|
let error = undefined;
|
|
750
959
|
await Promise.all([
|
|
751
960
|
sendNode(node),
|
|
752
|
-
waitForMsgMediaUpdate(update => {
|
|
961
|
+
waitForMsgMediaUpdate(async (update) => {
|
|
753
962
|
const result = update.find(c => c.key.id === message.key.id);
|
|
754
963
|
if (result) {
|
|
755
964
|
if (result.error) {
|
|
@@ -757,13 +966,16 @@ const makeMessagesSocket = (config) => {
|
|
|
757
966
|
}
|
|
758
967
|
else {
|
|
759
968
|
try {
|
|
760
|
-
const media =
|
|
761
|
-
if (media.result !==
|
|
762
|
-
const resultStr =
|
|
763
|
-
throw new
|
|
969
|
+
const media = await decryptMediaRetryData(result.media, mediaKey, result.key.id);
|
|
970
|
+
if (media.result !== proto.MediaRetryNotification.ResultType.SUCCESS) {
|
|
971
|
+
const resultStr = proto.MediaRetryNotification.ResultType[media.result];
|
|
972
|
+
throw new Boom(`Media re-upload failed by device (${resultStr})`, {
|
|
973
|
+
data: media,
|
|
974
|
+
statusCode: getStatusCodeForMediaRetry(media.result) || 404
|
|
975
|
+
});
|
|
764
976
|
}
|
|
765
977
|
content.directPath = media.directPath;
|
|
766
|
-
content.url =
|
|
978
|
+
content.url = getUrlFromDirectPath(content.directPath);
|
|
767
979
|
logger.debug({ directPath: media.directPath, key: result.key }, 'media update successful');
|
|
768
980
|
}
|
|
769
981
|
catch (err) {
|
|
@@ -777,133 +989,112 @@ const makeMessagesSocket = (config) => {
|
|
|
777
989
|
if (error) {
|
|
778
990
|
throw error;
|
|
779
991
|
}
|
|
780
|
-
ev.emit('messages.update', [
|
|
781
|
-
{
|
|
782
|
-
key: message.key,
|
|
783
|
-
update: {
|
|
784
|
-
message: message.message
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
]);
|
|
992
|
+
ev.emit('messages.update', [{ key: message.key, update: { message: message.message } }]);
|
|
788
993
|
return message;
|
|
789
994
|
},
|
|
790
995
|
sendMessage: async (jid, content, options = {}) => {
|
|
791
996
|
const userJid = authState.creds.me.id;
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
typeof
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
await groupToggleEphemeral(jid, value)
|
|
997
|
+
if (typeof content === 'object' &&
|
|
998
|
+
'disappearingMessagesInChat' in content &&
|
|
999
|
+
typeof content['disappearingMessagesInChat'] !== 'undefined' &&
|
|
1000
|
+
isJidGroup(jid)) {
|
|
1001
|
+
const { disappearingMessagesInChat } = content;
|
|
1002
|
+
const value = typeof disappearingMessagesInChat === 'boolean'
|
|
1003
|
+
? disappearingMessagesInChat
|
|
1004
|
+
? WA_DEFAULT_EPHEMERAL
|
|
1005
|
+
: 0
|
|
1006
|
+
: disappearingMessagesInChat;
|
|
1007
|
+
await groupToggleEphemeral(jid, value);
|
|
805
1008
|
}
|
|
806
|
-
|
|
807
1009
|
else {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
...
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
case 'INTERACTIVE':
|
|
829
|
-
const interactiveContent = await rahmi.handleInteractive(content, jid, quoted);
|
|
830
|
-
const interactiveMsg = await Utils_1.generateWAMessageFromContent(jid, interactiveContent, { quoted });
|
|
831
|
-
return await relayMessage(jid, interactiveMsg.message, {
|
|
832
|
-
messageId: interactiveMsg.key.id,
|
|
833
|
-
...getParticipantAttr()
|
|
1010
|
+
const fullMsg = await generateWAMessage(jid, content, {
|
|
1011
|
+
logger,
|
|
1012
|
+
userJid,
|
|
1013
|
+
getUrlInfo: text => getUrlInfo(text, {
|
|
1014
|
+
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
1015
|
+
fetchOpts: {
|
|
1016
|
+
timeout: 3000,
|
|
1017
|
+
...(httpRequestOptions || {})
|
|
1018
|
+
},
|
|
1019
|
+
logger,
|
|
1020
|
+
uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
|
|
1021
|
+
}),
|
|
1022
|
+
//TODO: CACHE
|
|
1023
|
+
getProfilePicUrl: sock.profilePictureUrl,
|
|
1024
|
+
getCallLink: sock.createCallLink,
|
|
1025
|
+
upload: async (readStream, opts) => {
|
|
1026
|
+
const up = await waUploadToServer(readStream, {
|
|
1027
|
+
...opts,
|
|
1028
|
+
newsletter: isJidNewsletter(jid)
|
|
834
1029
|
});
|
|
835
|
-
|
|
836
|
-
return await rahmi.handleAlbum(content, jid, quoted)
|
|
837
|
-
case 'EVENT':
|
|
838
|
-
return await rahmi.handleEvent(content, jid, quoted)
|
|
839
|
-
case 'POLL_RESULT':
|
|
840
|
-
return await rahmi.handlePollResult(content, jid, quoted)
|
|
841
|
-
case 'GROUP_STORY':
|
|
842
|
-
return await rahmi.handleGroupStory(content, jid, quoted)
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
const fullMsg = await Utils_1.generateWAMessage(jid, content, {
|
|
846
|
-
logger,
|
|
847
|
-
userJid,
|
|
848
|
-
quoted,
|
|
849
|
-
getUrlInfo: text => link_preview_1.getUrlInfo(text, {
|
|
850
|
-
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
851
|
-
fetchOpts: {
|
|
852
|
-
timeout: 3000,
|
|
853
|
-
...axiosOptions || {}
|
|
1030
|
+
return up;
|
|
854
1031
|
},
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
} else if (isAiMsg) {
|
|
884
|
-
additionalNodes.push({
|
|
1032
|
+
mediaCache: config.mediaCache,
|
|
1033
|
+
options: config.options,
|
|
1034
|
+
messageId: generateMessageIDV2(sock.user?.id),
|
|
1035
|
+
...options
|
|
1036
|
+
});
|
|
1037
|
+
const isAiMsg = 'ai' in content && !!content.ai;
|
|
1038
|
+
const isEventMsg = 'event' in content && !!content.event;
|
|
1039
|
+
const isDeleteMsg = 'delete' in content && !!content.delete;
|
|
1040
|
+
const isEditMsg = 'edit' in content && !!content.edit;
|
|
1041
|
+
const isPinMsg = 'pin' in content && !!content.pin;
|
|
1042
|
+
const isPollMessage = 'poll' in content && !!content.poll;
|
|
1043
|
+
const additionalAttributes = {};
|
|
1044
|
+
const additionalNodes = [];
|
|
1045
|
+
// required for delete
|
|
1046
|
+
if (isDeleteMsg) {
|
|
1047
|
+
// if the chat is a group, and I am not the author, then delete the message as an admin
|
|
1048
|
+
if (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe) {
|
|
1049
|
+
additionalAttributes.edit = '8';
|
|
1050
|
+
}
|
|
1051
|
+
else {
|
|
1052
|
+
additionalAttributes.edit = '7';
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
else if (isEditMsg) {
|
|
1056
|
+
additionalAttributes.edit = '1';
|
|
1057
|
+
}
|
|
1058
|
+
else if (isAiMsg) {
|
|
1059
|
+
additionalNodes.push({
|
|
885
1060
|
attrs: {
|
|
886
1061
|
biz_bot: '1'
|
|
887
1062
|
}, tag: "bot"
|
|
888
1063
|
});
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
1064
|
+
}
|
|
1065
|
+
else if (isPinMsg) {
|
|
1066
|
+
additionalAttributes.edit = '2';
|
|
1067
|
+
}
|
|
1068
|
+
else if (isPollMessage) {
|
|
1069
|
+
additionalNodes.push({
|
|
1070
|
+
tag: 'meta',
|
|
1071
|
+
attrs: {
|
|
1072
|
+
polltype: 'creation'
|
|
1073
|
+
}
|
|
1074
|
+
});
|
|
1075
|
+
}
|
|
1076
|
+
else if (isEventMsg) {
|
|
1077
|
+
additionalNodes.push({
|
|
1078
|
+
tag: 'meta',
|
|
1079
|
+
attrs: {
|
|
1080
|
+
event_type: 'creation'
|
|
1081
|
+
}
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
await relayMessage(jid, fullMsg.message, {
|
|
1085
|
+
messageId: fullMsg.key.id,
|
|
1086
|
+
useCachedGroupMetadata: options.useCachedGroupMetadata,
|
|
1087
|
+
additionalAttributes,
|
|
1088
|
+
statusJidList: options.statusJidList,
|
|
1089
|
+
additionalNodes: isAiMsg ? additionalNodes : options.additionalNodes
|
|
902
1090
|
});
|
|
903
|
-
|
|
904
|
-
|
|
1091
|
+
if (config.emitOwnEvents) {
|
|
1092
|
+
process.nextTick(() => {
|
|
1093
|
+
processingMutex.mutex(() => upsertMessage(fullMsg, 'append'));
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
return fullMsg;
|
|
905
1097
|
}
|
|
906
1098
|
}
|
|
907
|
-
}
|
|
908
|
-
};
|
|
909
|
-
exports.makeMessagesSocket = makeMessagesSocket;
|
|
1099
|
+
};
|
|
1100
|
+
};
|