@hansaka02/baileys 7.3.2 → 7.3.6
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/lib/Defaults/baileys-version.json +2 -2
- package/lib/Defaults/connection.js +51 -0
- package/lib/Defaults/constants.js +74 -0
- package/lib/Defaults/history.js +19 -0
- package/lib/Defaults/index.js +36 -142
- package/lib/Defaults/media.js +48 -0
- package/lib/Defaults/prefix.js +18 -0
- package/lib/Signal/Group/group-session-builder.js +10 -42
- package/lib/Signal/Group/group_cipher.js +9 -6
- package/lib/Signal/Group/index.js +39 -53
- package/lib/Signal/Group/keyhelper.js +8 -41
- package/lib/Signal/Group/sender-chain-key.js +5 -18
- package/lib/Signal/Group/sender-key-distribution-message.js +7 -7
- package/lib/Signal/Group/sender-key-message.js +12 -8
- package/lib/Signal/Group/sender-key-record.js +7 -16
- package/lib/Signal/Group/sender-key-state.js +15 -61
- package/lib/Signal/Group/sender-message-key.js +2 -2
- package/lib/Signal/libsignal.js +237 -177
- package/lib/Signal/lid-mapping.js +128 -71
- package/lib/Socket/Client/types.js +2 -2
- package/lib/Socket/Client/websocket.js +25 -16
- package/lib/Socket/business.js +46 -33
- package/lib/Socket/chats.js +286 -170
- package/lib/Socket/community.js +215 -77
- package/lib/Socket/groups.js +77 -61
- package/lib/Socket/index.js +4 -4
- package/lib/Socket/messages-recv.js +629 -457
- package/lib/Socket/messages-send.js +645 -656
- package/lib/Socket/mex.js +61 -0
- package/lib/Socket/newsletter.js +166 -245
- package/lib/Socket/socket.js +396 -170
- package/lib/Store/index.js +27 -11
- package/lib/Store/make-cache-manager-store.js +14 -15
- package/lib/Store/make-in-memory-store.js +28 -24
- package/lib/Types/LabelAssociation.js +2 -2
- package/lib/Types/Message.js +6 -6
- package/lib/Types/MexUpdates.js +5 -5
- package/lib/Types/Newsletter.js +32 -25
- package/lib/Types/State.js +4 -4
- package/lib/Types/index.js +28 -12
- package/lib/Utils/auth-utils.js +212 -375
- package/lib/Utils/baileys-event-stream.js +68 -69
- package/lib/Utils/browser-utils.js +43 -0
- package/lib/Utils/business.js +63 -53
- package/lib/Utils/chat-utils.js +241 -106
- package/lib/Utils/crypto.js +25 -45
- package/lib/Utils/decode-wa-message.js +361 -311
- package/lib/Utils/event-buffer.js +97 -42
- package/lib/Utils/generics.js +90 -207
- package/lib/Utils/history.js +29 -27
- package/lib/Utils/index.js +28 -14
- package/lib/Utils/link-preview.js +24 -62
- package/lib/Utils/logger.js +5 -5
- package/lib/Utils/lt-hash.js +29 -23
- package/lib/Utils/make-mutex.js +26 -28
- package/lib/Utils/message-retry-manager.js +55 -7
- package/lib/Utils/messages-media.js +434 -247
- package/lib/Utils/messages.js +963 -917
- package/lib/Utils/noise-handler.js +60 -20
- package/lib/Utils/pre-key-manager.js +126 -0
- package/lib/Utils/process-message.js +216 -141
- package/lib/Utils/signal.js +75 -37
- package/lib/Utils/use-multi-file-auth-state.js +18 -22
- package/lib/Utils/validate-connection.js +96 -66
- package/lib/WABinary/constants.js +1268 -1268
- package/lib/WABinary/decode.js +62 -34
- package/lib/WABinary/encode.js +57 -36
- package/lib/WABinary/generic-utils.js +4 -4
- package/lib/WABinary/index.js +27 -11
- package/lib/WABinary/jid-utils.js +58 -11
- package/lib/WAM/constants.js +19064 -11563
- package/lib/WAM/encode.js +71 -14
- package/lib/WAM/index.js +27 -11
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.js +20 -16
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +2 -2
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +7 -4
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +2 -2
- package/lib/WAUSync/Protocols/USyncLIDProtocol.js +0 -2
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +2 -2
- package/lib/WAUSync/Protocols/index.js +27 -11
- package/lib/WAUSync/USyncQuery.js +51 -28
- package/lib/WAUSync/index.js +27 -11
- package/lib/index.js +60 -31
- package/package.json +12 -17
- package/WAProto/AICommon/AICommon.d.ts +0 -11702
- package/WAProto/Adv/Adv.d.ts +0 -643
- package/WAProto/BotMetadata/BotMetadata.d.ts +0 -5654
- package/WAProto/Cert/Cert.d.ts +0 -613
- package/WAProto/ChatLockSettings/ChatLockSettings.d.ts +0 -476
- package/WAProto/CompanionReg/CompanionReg.d.ts +0 -1361
- package/WAProto/DeviceCapabilities/DeviceCapabilities.d.ts +0 -577
- package/WAProto/E2E/E2E.d.ts +0 -41724
- package/WAProto/Ephemeral/Ephemeral.d.ts +0 -114
- package/WAProto/HistorySync/HistorySync.d.ts +0 -51700
- package/WAProto/LidMigrationSyncPayload/LidMigrationSyncPayload.d.ts +0 -229
- package/WAProto/MdStorageChatRowOpaqueData/MdStorageChatRowOpaqueData.d.ts +0 -583
- package/WAProto/MdStorageMsgRowOpaqueData/MdStorageMsgRowOpaqueData.d.ts +0 -42897
- package/WAProto/MmsRetry/MmsRetry.d.ts +0 -243
- package/WAProto/Protocol/Protocol.d.ts +0 -270
- package/WAProto/Reporting/Reporting.d.ts +0 -371
- package/WAProto/ServerSync/ServerSync.d.ts +0 -1285
- package/WAProto/SignalLocalStorageProtocol/SignalLocalStorageProtocol.d.ts +0 -1868
- package/WAProto/SignalWhisperTextProtocol/SignalWhisperTextProtocol.d.ts +0 -767
- package/WAProto/StatusAttributions/StatusAttributions.d.ts +0 -1027
- package/WAProto/SyncAction/SyncAction.d.ts +0 -11193
- package/WAProto/UserPassword/UserPassword.d.ts +0 -363
- package/WAProto/VnameCert/VnameCert.d.ts +0 -821
- package/WAProto/Wa6/Wa6.d.ts +0 -2128
- package/WAProto/Web/Web.d.ts +0 -46383
- package/WAProto/index.d.ts +0 -55
- package/lib/Defaults/index.d.ts +0 -77
- package/lib/Signal/Group/ciphertext-message.d.ts +0 -9
- package/lib/Signal/Group/group-session-builder.d.ts +0 -17
- package/lib/Signal/Group/group_cipher.d.ts +0 -19
- package/lib/Signal/Group/index.d.ts +0 -11
- package/lib/Signal/Group/keyhelper.d.ts +0 -16
- package/lib/Signal/Group/sender-chain-key.d.ts +0 -14
- package/lib/Signal/Group/sender-key-distribution-message.d.ts +0 -17
- package/lib/Signal/Group/sender-key-message.d.ts +0 -19
- package/lib/Signal/Group/sender-key-name.d.ts +0 -19
- package/lib/Signal/Group/sender-key-record.d.ts +0 -32
- package/lib/Signal/Group/sender-key-state.d.ts +0 -44
- package/lib/Signal/Group/sender-message-key.d.ts +0 -11
- package/lib/Signal/libsignal.d.ts +0 -8
- package/lib/Signal/lid-mapping.d.ts +0 -28
- package/lib/Socket/Client/index.d.ts +0 -2
- package/lib/Socket/Client/types.d.ts +0 -16
- package/lib/Socket/Client/websocket.d.ts +0 -13
- package/lib/Socket/business.d.ts +0 -187
- package/lib/Socket/chats.d.ts +0 -97
- package/lib/Socket/community.d.ts +0 -129
- package/lib/Socket/groups.d.ts +0 -129
- package/lib/Socket/index.d.ts +0 -191
- package/lib/Socket/messages-recv.d.ts +0 -174
- package/lib/Socket/messages-send.d.ts +0 -165
- package/lib/Socket/newsletter.d.ts +0 -145
- package/lib/Socket/socket.d.ts +0 -45
- package/lib/Socket/usync.d.ts +0 -37
- package/lib/Socket/usync.js +0 -83
- package/lib/Store/index.d.ts +0 -4
- package/lib/Store/make-cache-manager-store.d.ts +0 -14
- package/lib/Store/make-in-memory-store.d.ts +0 -123
- package/lib/Store/make-ordered-dictionary.d.ts +0 -12
- package/lib/Store/object-repository.d.ts +0 -10
- package/lib/Types/Auth.d.ts +0 -121
- package/lib/Types/Bussiness.d.ts +0 -28
- package/lib/Types/Call.d.ts +0 -14
- package/lib/Types/Chat.d.ts +0 -143
- package/lib/Types/Contact.d.ts +0 -23
- package/lib/Types/Events.d.ts +0 -226
- package/lib/Types/GroupMetadata.d.ts +0 -66
- package/lib/Types/Label.d.ts +0 -48
- package/lib/Types/LabelAssociation.d.ts +0 -35
- package/lib/Types/Message.d.ts +0 -484
- package/lib/Types/MexUpdates.d.ts +0 -9
- package/lib/Types/Newsletter.d.ts +0 -109
- package/lib/Types/Product.d.ts +0 -92
- package/lib/Types/Signal.d.ts +0 -98
- package/lib/Types/Socket.d.ts +0 -141
- package/lib/Types/State.d.ts +0 -41
- package/lib/Types/USync.d.ts +0 -26
- package/lib/Types/index.d.ts +0 -80
- package/lib/Utils/auth-utils.d.ts +0 -21
- package/lib/Utils/baileys-event-stream.d.ts +0 -18
- package/lib/Utils/business.d.ts +0 -29
- package/lib/Utils/chat-utils.d.ts +0 -82
- package/lib/Utils/crypto.d.ts +0 -56
- package/lib/Utils/decode-wa-message.d.ts +0 -53
- package/lib/Utils/event-buffer.d.ts +0 -39
- package/lib/Utils/generics.d.ts +0 -117
- package/lib/Utils/history.d.ts +0 -23
- package/lib/Utils/index.d.ts +0 -20
- package/lib/Utils/link-preview.d.ts +0 -23
- package/lib/Utils/logger.d.ts +0 -13
- package/lib/Utils/lt-hash.d.ts +0 -14
- package/lib/Utils/make-mutex.d.ts +0 -9
- package/lib/Utils/message-retry-manager.d.ts +0 -88
- package/lib/Utils/messages-media.d.ts +0 -135
- package/lib/Utils/messages.d.ts +0 -105
- package/lib/Utils/noise-handler.d.ts +0 -20
- package/lib/Utils/process-message.d.ts +0 -49
- package/lib/Utils/signal.d.ts +0 -42
- package/lib/Utils/use-mongo-file-auth-state.d.ts +0 -6
- package/lib/Utils/use-mongo-file-auth-state.js +0 -84
- package/lib/Utils/use-multi-file-auth-state.d.ts +0 -13
- package/lib/Utils/use-single-file-auth-state.d.ts +0 -13
- package/lib/Utils/use-single-file-auth-state.js +0 -80
- package/lib/Utils/validate-connection.d.ts +0 -13
- package/lib/WABinary/constants.d.ts +0 -30
- package/lib/WABinary/decode.d.ts +0 -9
- package/lib/WABinary/encode.d.ts +0 -3
- package/lib/WABinary/generic-utils.d.ts +0 -28
- package/lib/WABinary/index.d.ts +0 -5
- package/lib/WABinary/jid-utils.d.ts +0 -58
- package/lib/WABinary/types.d.ts +0 -22
- package/lib/WAM/BinaryInfo.d.ts +0 -16
- package/lib/WAM/constants.d.ts +0 -47
- package/lib/WAM/encode.d.ts +0 -3
- package/lib/WAM/index.d.ts +0 -3
- package/lib/WAUSync/Protocols/USyncBotProfileProtocol.d.ts +0 -28
- package/lib/WAUSync/Protocols/USyncContactProtocol.d.ts +0 -10
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.d.ts +0 -26
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.d.ts +0 -14
- package/lib/WAUSync/Protocols/USyncLIDProtocol.d.ts +0 -10
- package/lib/WAUSync/Protocols/USyncStatusProtocol.d.ts +0 -14
- package/lib/WAUSync/Protocols/index.d.ts +0 -6
- package/lib/WAUSync/USyncQuery.d.ts +0 -31
- package/lib/WAUSync/USyncUser.d.ts +0 -12
- package/lib/WAUSync/index.d.ts +0 -3
- package/lib/index.d.ts +0 -13
|
@@ -1,76 +1,149 @@
|
|
|
1
1
|
"use strict"
|
|
2
2
|
|
|
3
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
-
return (mod && mod.__esModule) ? mod : { "default": mod }
|
|
5
|
-
}
|
|
6
|
-
|
|
7
3
|
Object.defineProperty(exports, "__esModule", { value: true })
|
|
8
4
|
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
5
|
+
const { default: NodeCache } = require("@cacheable/node-cache")
|
|
6
|
+
const { Boom } = require("@hapi/boom")
|
|
7
|
+
const { randomBytes } = require("crypto")
|
|
8
|
+
const { proto } = require("../../WAProto")
|
|
9
|
+
const {
|
|
10
|
+
DEFAULT_CACHE_TTLS,
|
|
11
|
+
WA_DEFAULT_EPHEMERAL
|
|
12
|
+
} = require("../Defaults/constants")
|
|
13
|
+
const {
|
|
14
|
+
delay,
|
|
15
|
+
assertMediaContent,
|
|
16
|
+
bindWaitForEvent,
|
|
17
|
+
decryptMediaRetryData,
|
|
18
|
+
encodeNewsletterMessage,
|
|
19
|
+
encodeSignedDeviceIdentity,
|
|
20
|
+
encodeWAMessage,
|
|
21
|
+
encryptMediaRetryRequest,
|
|
22
|
+
extractDeviceJids,
|
|
23
|
+
generateMessageID,
|
|
24
|
+
generateParticipantHashV2,
|
|
25
|
+
generateWAMessage,
|
|
26
|
+
generateWAMessageFromContent,
|
|
27
|
+
getStatusCodeForMediaRetry,
|
|
28
|
+
getUrlFromDirectPath,
|
|
29
|
+
getWAUploadToServer,
|
|
30
|
+
MessageRetryManager,
|
|
31
|
+
normalizeMessageContent,
|
|
32
|
+
parseAndInjectE2ESessions,
|
|
33
|
+
unixTimestampSeconds,
|
|
34
|
+
prepareAlbumMessageContent,
|
|
35
|
+
aggregateMessageKeysNotFromMe
|
|
36
|
+
} = require("../Utils")
|
|
37
|
+
const { WAMessageAddressingMode } = require("../Types")
|
|
38
|
+
const {
|
|
39
|
+
areJidsSameUser,
|
|
40
|
+
getBinaryNodeChild,
|
|
41
|
+
getBinaryNodeChildren,
|
|
42
|
+
getBinaryFilteredBizBot,
|
|
43
|
+
getBinaryFilteredButtons,
|
|
44
|
+
isHostedLidUser,
|
|
45
|
+
isHostedPnUser,
|
|
46
|
+
isJidNewsletter,
|
|
47
|
+
isJidGroup,
|
|
48
|
+
isLidUser,
|
|
49
|
+
isPnUser,
|
|
50
|
+
jidDecode,
|
|
51
|
+
jidEncode,
|
|
52
|
+
jidNormalizedUser,
|
|
53
|
+
STORIES_JID,
|
|
54
|
+
S_WHATSAPP_NET
|
|
55
|
+
} = require("../WABinary")
|
|
56
|
+
const {
|
|
57
|
+
USyncUser,
|
|
58
|
+
USyncQuery
|
|
59
|
+
} = require("../WAUSync")
|
|
60
|
+
const { makeNewsletterSocket } = require("./newsletter")
|
|
61
|
+
const { getUrlInfo } = require("../Utils/link-preview")
|
|
62
|
+
const { makeKeyedMutex } = require("../Utils/make-mutex")
|
|
21
63
|
|
|
22
64
|
const makeMessagesSocket = (config) => {
|
|
23
|
-
const {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
65
|
+
const {
|
|
66
|
+
logger,
|
|
67
|
+
linkPreviewImageThumbnailWidth,
|
|
68
|
+
generateHighQualityLinkPreview,
|
|
69
|
+
options: httpRequestOptions,
|
|
70
|
+
patchMessageBeforeSending,
|
|
71
|
+
cachedGroupMetadata,
|
|
72
|
+
enableRecentMessageCache,
|
|
73
|
+
maxMsgRetryCount
|
|
74
|
+
} = config
|
|
75
|
+
|
|
76
|
+
const suki = makeNewsletterSocket(config)
|
|
77
|
+
|
|
78
|
+
const {
|
|
79
|
+
ev,
|
|
80
|
+
authState,
|
|
81
|
+
messageMutex,
|
|
82
|
+
signalRepository,
|
|
83
|
+
upsertMessage,
|
|
84
|
+
createCallLink,
|
|
85
|
+
query,
|
|
86
|
+
fetchPrivacySettings,
|
|
87
|
+
sendNode,
|
|
88
|
+
groupQuery,
|
|
89
|
+
groupMetadata,
|
|
90
|
+
groupToggleEphemeral,
|
|
91
|
+
executeUSyncQuery,
|
|
92
|
+
newsletterMetadata
|
|
93
|
+
} = suki
|
|
94
|
+
|
|
95
|
+
const userDevicesCache = config.userDevicesCache || new NodeCache({
|
|
96
|
+
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
|
|
97
|
+
useClones: false
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
const peerSessionsCache = new NodeCache({
|
|
101
|
+
stdTTL: DEFAULT_CACHE_TTLS.USER_DEVICES,
|
|
29
102
|
useClones: false
|
|
30
103
|
})
|
|
31
104
|
|
|
32
105
|
// Initialize message retry manager if enabled
|
|
33
|
-
const messageRetryManager = enableRecentMessageCache ? new
|
|
106
|
+
const messageRetryManager = enableRecentMessageCache ? new MessageRetryManager(logger, maxMsgRetryCount) : null
|
|
34
107
|
|
|
35
108
|
// Prevent race conditions in Signal session encryption by user
|
|
36
|
-
const encryptionMutex =
|
|
109
|
+
const encryptionMutex = makeKeyedMutex()
|
|
37
110
|
|
|
38
111
|
let mediaConn
|
|
39
112
|
|
|
40
113
|
const refreshMediaConn = async (forceGet = false) => {
|
|
41
114
|
const media = await mediaConn
|
|
42
|
-
|
|
43
|
-
if (!media || forceGet ||
|
|
115
|
+
|
|
116
|
+
if (!media || forceGet || new Date().getTime() - media.fetchDate.getTime() > media.ttl * 1000) {
|
|
44
117
|
mediaConn = (async () => {
|
|
45
|
-
|
|
46
118
|
const result = await query({
|
|
47
119
|
tag: 'iq',
|
|
48
120
|
attrs: {
|
|
49
121
|
type: 'set',
|
|
50
122
|
xmlns: 'w:m',
|
|
51
|
-
to:
|
|
123
|
+
to: S_WHATSAPP_NET
|
|
52
124
|
},
|
|
53
125
|
content: [{ tag: 'media_conn', attrs: {} }]
|
|
54
126
|
})
|
|
55
|
-
|
|
56
|
-
const mediaConnNode =
|
|
57
|
-
|
|
127
|
+
|
|
128
|
+
const mediaConnNode = getBinaryNodeChild(result, 'media_conn')
|
|
129
|
+
|
|
130
|
+
// TODO: explore full length of data that whatsapp provides
|
|
58
131
|
const node = {
|
|
59
|
-
hosts:
|
|
132
|
+
hosts: getBinaryNodeChildren(mediaConnNode, 'host').map(({ attrs }) => ({
|
|
60
133
|
hostname: attrs.hostname,
|
|
61
|
-
maxContentLengthBytes: +attrs.maxContentLengthBytes
|
|
134
|
+
maxContentLengthBytes: +attrs.maxContentLengthBytes
|
|
62
135
|
})),
|
|
63
136
|
auth: mediaConnNode.attrs.auth,
|
|
64
137
|
ttl: +mediaConnNode.attrs.ttl,
|
|
65
138
|
fetchDate: new Date()
|
|
66
139
|
}
|
|
67
|
-
|
|
140
|
+
|
|
68
141
|
logger.debug('fetched media conn')
|
|
69
|
-
|
|
142
|
+
|
|
70
143
|
return node
|
|
71
144
|
})()
|
|
72
145
|
}
|
|
73
|
-
|
|
146
|
+
|
|
74
147
|
return mediaConn
|
|
75
148
|
}
|
|
76
149
|
|
|
@@ -79,37 +152,42 @@ const makeMessagesSocket = (config) => {
|
|
|
79
152
|
* used for receipts of phone call, read, delivery etc.
|
|
80
153
|
* */
|
|
81
154
|
const sendReceipt = async (jid, participant, messageIds, type) => {
|
|
155
|
+
if (!messageIds || messageIds.length === 0) {
|
|
156
|
+
throw new Boom('missing ids in receipt')
|
|
157
|
+
}
|
|
158
|
+
|
|
82
159
|
const node = {
|
|
83
160
|
tag: 'receipt',
|
|
84
161
|
attrs: {
|
|
85
|
-
id: messageIds[0]
|
|
86
|
-
}
|
|
162
|
+
id: messageIds[0]
|
|
163
|
+
}
|
|
87
164
|
}
|
|
88
|
-
|
|
165
|
+
|
|
89
166
|
const isReadReceipt = type === 'read' || type === 'read-self'
|
|
90
|
-
|
|
167
|
+
|
|
91
168
|
if (isReadReceipt) {
|
|
92
|
-
node.attrs.t =
|
|
169
|
+
node.attrs.t = unixTimestampSeconds().toString()
|
|
93
170
|
}
|
|
94
|
-
|
|
95
|
-
if (type === 'sender' &&
|
|
171
|
+
|
|
172
|
+
if (type === 'sender' && (isPnUser(jid) || isLidUser(jid))) {
|
|
96
173
|
node.attrs.recipient = jid
|
|
97
174
|
node.attrs.to = participant
|
|
98
175
|
}
|
|
99
|
-
|
|
176
|
+
|
|
100
177
|
else {
|
|
101
178
|
node.attrs.to = jid
|
|
179
|
+
|
|
102
180
|
if (participant) {
|
|
103
181
|
node.attrs.participant = participant
|
|
104
182
|
}
|
|
105
183
|
}
|
|
106
|
-
|
|
184
|
+
|
|
107
185
|
if (type) {
|
|
108
|
-
node.attrs.type =
|
|
186
|
+
node.attrs.type = type
|
|
109
187
|
}
|
|
110
|
-
|
|
188
|
+
|
|
111
189
|
const remainingMessageIds = messageIds.slice(1)
|
|
112
|
-
|
|
190
|
+
|
|
113
191
|
if (remainingMessageIds.length) {
|
|
114
192
|
node.content = [
|
|
115
193
|
{
|
|
@@ -122,15 +200,15 @@ const makeMessagesSocket = (config) => {
|
|
|
122
200
|
}
|
|
123
201
|
]
|
|
124
202
|
}
|
|
125
|
-
|
|
203
|
+
|
|
126
204
|
logger.debug({ attrs: node.attrs, messageIds }, 'sending receipt for messages')
|
|
127
|
-
|
|
205
|
+
|
|
128
206
|
await sendNode(node)
|
|
129
207
|
}
|
|
130
208
|
|
|
131
209
|
/** Correctly bulk send receipts to multiple chats, participants */
|
|
132
210
|
const sendReceipts = async (keys, type) => {
|
|
133
|
-
const recps =
|
|
211
|
+
const recps = aggregateMessageKeysNotFromMe(keys)
|
|
134
212
|
|
|
135
213
|
for (const { jid, participant, messageIds } of recps) {
|
|
136
214
|
await sendReceipt(jid, participant, messageIds, type)
|
|
@@ -147,84 +225,6 @@ const makeMessagesSocket = (config) => {
|
|
|
147
225
|
await sendReceipts(keys, readType)
|
|
148
226
|
}
|
|
149
227
|
|
|
150
|
-
/**
|
|
151
|
-
* Deduplicate JIDs when both LID and PN versions exist for same user
|
|
152
|
-
* Prefers LID over PN to maintain single encryption layer
|
|
153
|
-
*/
|
|
154
|
-
const deduplicateLidPnJids = (jids) => {
|
|
155
|
-
const lidUsers = new Set()
|
|
156
|
-
const filteredJids = []
|
|
157
|
-
|
|
158
|
-
// Collect all LID users
|
|
159
|
-
for (const jid of jids) {
|
|
160
|
-
if (WABinary_1.isLidUser(jid)) {
|
|
161
|
-
const user = WABinary_1.jidDecode(jid)?.user
|
|
162
|
-
if (user)
|
|
163
|
-
lidUsers.add(user)
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Filter out PN versions when LID exists
|
|
168
|
-
for (const jid of jids) {
|
|
169
|
-
if (WABinary_1.isJidUser(jid)) {
|
|
170
|
-
const user = WABinary_1.jidDecode(jid)?.user
|
|
171
|
-
if (user && lidUsers.has(user)) {
|
|
172
|
-
logger.debug({ jid }, 'Skipping PN - LID version exists')
|
|
173
|
-
continue
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
filteredJids.push(jid)
|
|
177
|
-
}
|
|
178
|
-
return filteredJids
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/** Fetch image for groups, user, and newsletter **/
|
|
182
|
-
const profilePictureUrl = async (jid) => {
|
|
183
|
-
if (WABinary_1.isJidNewsletter(jid)) {
|
|
184
|
-
|
|
185
|
-
let node = await newsletterWMexQuery(undefined, Types_1.QueryIds.METADATA, {
|
|
186
|
-
input: {
|
|
187
|
-
key: jid,
|
|
188
|
-
type: 'JID',
|
|
189
|
-
view_role: 'GUEST'
|
|
190
|
-
},
|
|
191
|
-
fetch_viewer_metadata: true,
|
|
192
|
-
fetch_full_image: true,
|
|
193
|
-
fetch_creation_time: true
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
let result = WABinary_1.getBinaryNodeChild(node, 'result')?.content?.toString()
|
|
197
|
-
|
|
198
|
-
let metadata = JSON.parse(result).data[Types_1.XWAPaths.NEWSLETTER]
|
|
199
|
-
|
|
200
|
-
return Utils_1.getUrlFromDirectPath(metadata.thread_metadata.picture?.direct_path || '')
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
else {
|
|
205
|
-
const result = await query({
|
|
206
|
-
tag: 'iq',
|
|
207
|
-
attrs: {
|
|
208
|
-
target: WABinary_1.jidNormalizedUser(jid),
|
|
209
|
-
to: WABinary_1.S_WHATSAPP_NET,
|
|
210
|
-
type: 'get',
|
|
211
|
-
xmlns: 'w:profile:picture'
|
|
212
|
-
},
|
|
213
|
-
content: [{
|
|
214
|
-
tag: 'picture',
|
|
215
|
-
attrs: {
|
|
216
|
-
type: 'image',
|
|
217
|
-
query: 'url'
|
|
218
|
-
}
|
|
219
|
-
}]
|
|
220
|
-
})
|
|
221
|
-
|
|
222
|
-
const child = WABinary_1.getBinaryNodeChild(result, 'picture')
|
|
223
|
-
|
|
224
|
-
return child?.attrs?.url || null
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
228
|
/** Fetch all the devices we've to send a message to */
|
|
229
229
|
const getUSyncDevices = async (jids, useCache, ignoreZeroDevices) => {
|
|
230
230
|
const deviceResults = []
|
|
@@ -235,10 +235,9 @@ const makeMessagesSocket = (config) => {
|
|
|
235
235
|
|
|
236
236
|
const toFetch = []
|
|
237
237
|
|
|
238
|
-
jids = deduplicateLidPnJids(Array.from(new Set(jids)))
|
|
239
238
|
const jidsWithUser = jids
|
|
240
239
|
.map(jid => {
|
|
241
|
-
const decoded =
|
|
240
|
+
const decoded = jidDecode(jid)
|
|
242
241
|
const user = decoded?.user
|
|
243
242
|
const device = decoded?.device
|
|
244
243
|
const isExplicitDevice = typeof device === 'number' && device >= 0
|
|
@@ -247,20 +246,22 @@ const makeMessagesSocket = (config) => {
|
|
|
247
246
|
deviceResults.push({
|
|
248
247
|
user,
|
|
249
248
|
device,
|
|
250
|
-
|
|
251
|
-
})
|
|
249
|
+
jid
|
|
250
|
+
})
|
|
251
|
+
|
|
252
252
|
return null
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
jid =
|
|
255
|
+
jid = jidNormalizedUser(jid)
|
|
256
|
+
|
|
256
257
|
return { jid, user }
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
|
|
258
|
+
}).filter(jid => jid !== null)
|
|
259
|
+
|
|
260
260
|
let mgetDevices
|
|
261
261
|
|
|
262
262
|
if (useCache && userDevicesCache.mget) {
|
|
263
263
|
const usersToFetch = jidsWithUser.map(j => j?.user).filter(Boolean)
|
|
264
|
+
|
|
264
265
|
mgetDevices = await userDevicesCache.mget(usersToFetch)
|
|
265
266
|
}
|
|
266
267
|
|
|
@@ -270,19 +271,21 @@ const makeMessagesSocket = (config) => {
|
|
|
270
271
|
(userDevicesCache.mget ? undefined : (await userDevicesCache.get(user)))
|
|
271
272
|
|
|
272
273
|
if (devices) {
|
|
273
|
-
const
|
|
274
|
-
const devicesWithWire = devices.map(d => ({
|
|
274
|
+
const devicesWithJid = devices.map(d => ({
|
|
275
275
|
...d,
|
|
276
|
-
|
|
276
|
+
jid: jidEncode(d.user, d.server, d.device)
|
|
277
277
|
}))
|
|
278
278
|
|
|
279
|
-
deviceResults.push(...
|
|
279
|
+
deviceResults.push(...devicesWithJid)
|
|
280
|
+
|
|
280
281
|
logger.trace({ user }, 'using cache for devices')
|
|
281
282
|
}
|
|
283
|
+
|
|
282
284
|
else {
|
|
283
285
|
toFetch.push(jid)
|
|
284
286
|
}
|
|
285
287
|
}
|
|
288
|
+
|
|
286
289
|
else {
|
|
287
290
|
toFetch.push(jid)
|
|
288
291
|
}
|
|
@@ -293,23 +296,49 @@ const makeMessagesSocket = (config) => {
|
|
|
293
296
|
}
|
|
294
297
|
|
|
295
298
|
const requestedLidUsers = new Set()
|
|
299
|
+
|
|
296
300
|
for (const jid of toFetch) {
|
|
297
|
-
if (
|
|
298
|
-
const user =
|
|
301
|
+
if (isLidUser(jid) || isHostedLidUser(jid)) {
|
|
302
|
+
const user = jidDecode(jid)?.user
|
|
303
|
+
|
|
299
304
|
if (user)
|
|
300
305
|
requestedLidUsers.add(user)
|
|
301
306
|
}
|
|
302
307
|
}
|
|
303
308
|
|
|
304
|
-
const query = new
|
|
309
|
+
const query = new USyncQuery().withContext('message').withDeviceProtocol().withLIDProtocol()
|
|
310
|
+
|
|
305
311
|
for (const jid of toFetch) {
|
|
306
|
-
query.withUser(new
|
|
312
|
+
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
|
|
307
313
|
}
|
|
308
314
|
|
|
309
315
|
const result = await executeUSyncQuery(query)
|
|
310
316
|
|
|
311
317
|
if (result) {
|
|
312
|
-
|
|
318
|
+
// TODO: LID MAP this stuff (lid protocol will now return lid with devices)
|
|
319
|
+
const lidResults = result.list.filter(a => !!a.lid)
|
|
320
|
+
|
|
321
|
+
if (lidResults.length > 0) {
|
|
322
|
+
logger.trace('Storing LID maps from device call')
|
|
323
|
+
|
|
324
|
+
await signalRepository.lidMapping.storeLIDPNMappings(lidResults.map(a => ({ lid: a.lid, pn: a.id })))
|
|
325
|
+
|
|
326
|
+
// Force-refresh sessions for newly mapped LIDs to align identity addressing
|
|
327
|
+
try {
|
|
328
|
+
const lids = lidResults.map(a => a.lid)
|
|
329
|
+
|
|
330
|
+
if (lids.length) {
|
|
331
|
+
await assertSessions(lids, true)
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
catch (e) {
|
|
336
|
+
logger.warn({ e, count: lidResults.length }, 'failed to assert sessions for newly mapped LIDs')
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const extracted = extractDeviceJids(result?.list, authState.creds.me.id, authState.creds.me.lid, ignoreZeroDevices)
|
|
341
|
+
|
|
313
342
|
const deviceMap = {}
|
|
314
343
|
|
|
315
344
|
for (const item of extracted) {
|
|
@@ -319,22 +348,21 @@ const makeMessagesSocket = (config) => {
|
|
|
319
348
|
|
|
320
349
|
// Process each user's devices as a group for bulk LID migration
|
|
321
350
|
for (const [user, userDevices] of Object.entries(deviceMap)) {
|
|
322
|
-
const isLidUser = requestedLidUsers.has(user)
|
|
323
|
-
|
|
351
|
+
const isLidUser = requestedLidUsers.has(user);
|
|
324
352
|
// Process all devices for this user
|
|
325
353
|
for (const item of userDevices) {
|
|
326
|
-
const
|
|
327
|
-
?
|
|
328
|
-
:
|
|
354
|
+
const finalJid = isLidUser
|
|
355
|
+
? jidEncode(user, item.server, item.device)
|
|
356
|
+
: jidEncode(item.user, item.server, item.device)
|
|
329
357
|
deviceResults.push({
|
|
330
358
|
...item,
|
|
331
|
-
|
|
332
|
-
})
|
|
359
|
+
jid: finalJid
|
|
360
|
+
})
|
|
333
361
|
|
|
334
362
|
logger.debug({
|
|
335
363
|
user: item.user,
|
|
336
364
|
device: item.device,
|
|
337
|
-
|
|
365
|
+
finalJid,
|
|
338
366
|
usedLid: isLidUser
|
|
339
367
|
}, 'Processed device with LID priority')
|
|
340
368
|
}
|
|
@@ -352,331 +380,204 @@ const makeMessagesSocket = (config) => {
|
|
|
352
380
|
}
|
|
353
381
|
}
|
|
354
382
|
|
|
355
|
-
|
|
356
|
-
return deviceResults
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
const assertSessions = async (jids, force) => {
|
|
360
|
-
let didFetchNewSession = false
|
|
361
|
-
const jidsRequiringFetch = []
|
|
362
|
-
|
|
363
|
-
// Apply same deduplication as in getUSyncDevices
|
|
364
|
-
jids = deduplicateLidPnJids(jids)
|
|
365
|
-
|
|
366
|
-
if (force) {
|
|
367
|
-
// Check which sessions are missing (with LID migration check)
|
|
368
|
-
const addrs = jids.map(jid => signalRepository.jidToSignalProtocolAddress(jid))
|
|
369
|
-
const sessions = await authState.keys.get('session', addrs)
|
|
383
|
+
const userDeviceUpdates = {}
|
|
370
384
|
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
// Add to fetch list if no session exists
|
|
376
|
-
// Session type selection (LID vs PN) is handled in encryptMessage
|
|
377
|
-
if (!hasSession) {
|
|
378
|
-
if (jid.includes('@lid')) {
|
|
379
|
-
logger.debug({ jid }, 'No LID session found, will create new LID session')
|
|
380
|
-
}
|
|
381
|
-
jidsRequiringFetch.push(jid)
|
|
385
|
+
for (const [userId, devices] of Object.entries(deviceMap)) {
|
|
386
|
+
if (devices && devices.length > 0) {
|
|
387
|
+
userDeviceUpdates[userId] = devices.map(d => d.device?.toString() || '0')
|
|
382
388
|
}
|
|
383
389
|
}
|
|
384
390
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
391
|
+
if (Object.keys(userDeviceUpdates).length > 0) {
|
|
392
|
+
try {
|
|
393
|
+
await authState.keys.set({ 'device-list': userDeviceUpdates })
|
|
394
|
+
|
|
395
|
+
logger.debug({ userCount: Object.keys(userDeviceUpdates).length }, 'stored user device lists for bulk migration')
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
catch (error) {
|
|
399
|
+
logger.warn({ error }, 'failed to store user device lists')
|
|
400
|
+
}
|
|
388
401
|
}
|
|
389
402
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
403
|
+
|
|
404
|
+
return deviceResults
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const updateMemberLabel = (jid, memberLabel) => {
|
|
408
|
+
if (!isJidGroup(jid)) {
|
|
409
|
+
throw new Error('Jid must a group!')
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const protocolMessage = {
|
|
413
|
+
protocolMessage: {
|
|
414
|
+
type: proto.Message.ProtocolMessage.Type.GROUP_MEMBER_LABEL_CHANGE,
|
|
415
|
+
memberLabel: {
|
|
416
|
+
label: memberLabel?.slice(0, 30),
|
|
417
|
+
labelTimestamp: unixTimestampSeconds()
|
|
400
418
|
}
|
|
401
|
-
userGroups.get(user).push(jid)
|
|
402
419
|
}
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const pnJid = `${user}@s.whatsapp.net`
|
|
413
|
-
const mapping = await signalRepository.lidMapping.getLIDForPN(pnJid)
|
|
414
|
-
|
|
415
|
-
if (mapping?.includes('@lid')) {
|
|
416
|
-
logger.debug({ user, lidForPN: mapping, deviceCount: userJids.length }, 'User has LID mapping - preparing bulk migration')
|
|
417
|
-
return { shouldMigrate: true, lidForPN: mapping }
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return relayMessage(jid, protocolMessage, {
|
|
423
|
+
additionalNodes: [
|
|
424
|
+
{
|
|
425
|
+
tag: 'meta',
|
|
426
|
+
attrs: {
|
|
427
|
+
tag_reason: 'user_update',
|
|
428
|
+
appdata: 'member_tag'
|
|
418
429
|
}
|
|
419
430
|
}
|
|
420
|
-
|
|
421
|
-
|
|
431
|
+
]
|
|
432
|
+
})
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const assertSessions = async (jids, force) => {
|
|
436
|
+
let didFetchNewSession = false
|
|
437
|
+
|
|
438
|
+
const uniqueJids = [...new Set(jids)] // Deduplicate JIDs
|
|
439
|
+
const jidsRequiringFetch = []
|
|
440
|
+
|
|
441
|
+
logger.debug({ jids }, 'assertSessions call with jids')
|
|
442
|
+
|
|
443
|
+
// Check peerSessionsCache and validate sessions using libsignal loadSession
|
|
444
|
+
for (const jid of uniqueJids) {
|
|
445
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(jid)
|
|
446
|
+
const cachedSession = peerSessionsCache.get(signalId)
|
|
447
|
+
|
|
448
|
+
if (cachedSession !== undefined) {
|
|
449
|
+
if (cachedSession && !force) {
|
|
450
|
+
continue // Session exists in cache
|
|
422
451
|
}
|
|
423
|
-
|
|
424
|
-
return { shouldMigrate: false, lidForPN: undefined }
|
|
425
452
|
}
|
|
426
453
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
const
|
|
430
|
-
const shouldMigrateUser = mappingResult.shouldMigrate
|
|
431
|
-
const lidForPN = mappingResult.lidForPN
|
|
454
|
+
else {
|
|
455
|
+
const sessionValidation = await signalRepository.validateSession(jid)
|
|
456
|
+
const hasSession = sessionValidation.exists
|
|
432
457
|
|
|
433
|
-
|
|
434
|
-
if (shouldMigrateUser && lidForPN) {
|
|
435
|
-
// Bulk migrate all user devices in single transaction
|
|
436
|
-
const migrationResult = await signalRepository.migrateSession(userJids, lidForPN)
|
|
437
|
-
|
|
438
|
-
if (migrationResult.migrated > 0) {
|
|
439
|
-
logger.info({
|
|
440
|
-
user,
|
|
441
|
-
lidMapping: lidForPN,
|
|
442
|
-
migrated: migrationResult.migrated,
|
|
443
|
-
skipped: migrationResult.skipped,
|
|
444
|
-
total: migrationResult.total
|
|
445
|
-
}, 'Completed bulk migration for user devices');
|
|
446
|
-
}
|
|
447
|
-
else {
|
|
448
|
-
logger.debug({
|
|
449
|
-
user,
|
|
450
|
-
lidMapping: lidForPN,
|
|
451
|
-
skipped: migrationResult.skipped,
|
|
452
|
-
total: migrationResult.total
|
|
453
|
-
}, 'All user device sessions already migrated');
|
|
454
|
-
}
|
|
455
|
-
}
|
|
458
|
+
peerSessionsCache.set(signalId, hasSession)
|
|
456
459
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
const signalId = signalRepository.jidToSignalProtocolAddress(jid)
|
|
460
|
-
|
|
461
|
-
if (sessions[signalId]) return
|
|
462
|
-
|
|
463
|
-
// Determine correct JID to fetch (LID if mapping exists, otherwise original)
|
|
464
|
-
if (jid.includes('@s.whatsapp.net') && shouldMigrateUser && lidForPN) {
|
|
465
|
-
const decoded = WABinary_1.jidDecode(jid)
|
|
466
|
-
const lidDeviceJid = decoded.device !== undefined ? `${WABinary_1.jidDecode(lidForPN).user}:${decoded.device}@lid` : lidForPN
|
|
467
|
-
|
|
468
|
-
jidsRequiringFetch.push(lidDeviceJid)
|
|
469
|
-
logger.debug({ pnJid: jid, lidJid: lidDeviceJid }, 'Adding LID JID to fetch list (conversion)')
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
else {
|
|
473
|
-
jidsRequiringFetch.push(jid)
|
|
474
|
-
logger.debug({ jid }, 'Adding JID to fetch list')
|
|
475
|
-
}
|
|
460
|
+
if (hasSession && !force) {
|
|
461
|
+
continue
|
|
476
462
|
}
|
|
477
|
-
|
|
478
|
-
userJids.forEach(addMissingSessionsToFetchList)
|
|
479
463
|
}
|
|
464
|
+
|
|
465
|
+
jidsRequiringFetch.push(jid)
|
|
480
466
|
}
|
|
481
467
|
|
|
482
468
|
if (jidsRequiringFetch.length) {
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
for (const jid of jidsRequiringFetch) {
|
|
490
|
-
const user = WABinary_1.jidDecode(jid)?.user
|
|
491
|
-
|
|
492
|
-
if (user) {
|
|
493
|
-
if (WABinary_1.isLidUser(jid)) {
|
|
494
|
-
lidUsersBeingFetched.add(user)
|
|
495
|
-
}
|
|
496
|
-
else if (WABinary_1.isJidUser(jid)) {
|
|
497
|
-
pnUsersBeingFetched.add(user)
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
}
|
|
469
|
+
// LID if mapped, otherwise original
|
|
470
|
+
const wireJids = [
|
|
471
|
+
...jidsRequiringFetch.filter(jid => !!isLidUser(jid) || !!isHostedLidUser(jid)),
|
|
472
|
+
...((await signalRepository.lidMapping.getLIDsForPNs(jidsRequiringFetch.filter(jid => !!isPnUser(jid) || !!isHostedPnUser(jid)))) || []).map(a => a.lid)
|
|
473
|
+
]
|
|
501
474
|
|
|
502
|
-
|
|
503
|
-
const overlapping = Array.from(pnUsersBeingFetched).filter(user => lidUsersBeingFetched.has(user))
|
|
504
|
-
if (overlapping.length > 0) {
|
|
505
|
-
logger.warn({
|
|
506
|
-
overlapping,
|
|
507
|
-
lidUsersBeingFetched: Array.from(lidUsersBeingFetched),
|
|
508
|
-
pnUsersBeingFetched: Array.from(pnUsersBeingFetched)
|
|
509
|
-
}, 'Fetching both LID and PN sessions for same users')
|
|
510
|
-
}
|
|
475
|
+
logger.debug({ jidsRequiringFetch, wireJids }, 'fetching sessions')
|
|
511
476
|
|
|
512
477
|
const result = await query({
|
|
513
478
|
tag: 'iq',
|
|
514
479
|
attrs: {
|
|
515
480
|
xmlns: 'encrypt',
|
|
516
481
|
type: 'get',
|
|
517
|
-
to:
|
|
482
|
+
to: S_WHATSAPP_NET
|
|
518
483
|
},
|
|
519
484
|
content: [
|
|
520
485
|
{
|
|
521
486
|
tag: 'key',
|
|
522
487
|
attrs: {},
|
|
523
|
-
content:
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
488
|
+
content: wireJids.map(jid => {
|
|
489
|
+
const attrs = { jid }
|
|
490
|
+
|
|
491
|
+
if (force) attrs.reason = 'identity'
|
|
492
|
+
|
|
493
|
+
return { tag: 'user', attrs }
|
|
494
|
+
})
|
|
527
495
|
}
|
|
528
496
|
]
|
|
529
497
|
})
|
|
530
498
|
|
|
531
|
-
await
|
|
499
|
+
await parseAndInjectE2ESessions(result, signalRepository)
|
|
500
|
+
|
|
532
501
|
didFetchNewSession = true
|
|
502
|
+
|
|
503
|
+
// Cache fetched sessions using wire JIDs
|
|
504
|
+
for (const wireJid of wireJids) {
|
|
505
|
+
const signalId = signalRepository.jidToSignalProtocolAddress(wireJid)
|
|
506
|
+
peerSessionsCache.set(signalId, true)
|
|
507
|
+
}
|
|
533
508
|
}
|
|
509
|
+
|
|
534
510
|
return didFetchNewSession
|
|
535
511
|
}
|
|
536
|
-
|
|
537
|
-
/** Send Peer Operation */
|
|
512
|
+
|
|
538
513
|
const sendPeerDataOperationMessage = async (pdoMessage) => {
|
|
539
514
|
//TODO: for later, abstract the logic to send a Peer Message instead of just PDO - useful for App State Key Resync with phone
|
|
540
515
|
if (!authState.creds.me?.id) {
|
|
541
|
-
throw new
|
|
516
|
+
throw new Boom('Not authenticated')
|
|
542
517
|
}
|
|
543
|
-
|
|
518
|
+
|
|
544
519
|
const protocolMessage = {
|
|
545
520
|
protocolMessage: {
|
|
546
521
|
peerDataOperationRequestMessage: pdoMessage,
|
|
547
|
-
type:
|
|
522
|
+
type: proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_MESSAGE
|
|
548
523
|
}
|
|
549
524
|
}
|
|
550
|
-
|
|
551
|
-
const meJid =
|
|
552
|
-
|
|
525
|
+
|
|
526
|
+
const meJid = jidNormalizedUser(authState.creds.me.id)
|
|
553
527
|
const msgId = await relayMessage(meJid, protocolMessage, {
|
|
554
528
|
additionalAttributes: {
|
|
555
529
|
category: 'peer',
|
|
556
|
-
|
|
557
|
-
push_priority: 'high_force',
|
|
530
|
+
push_priority: 'high_force'
|
|
558
531
|
},
|
|
532
|
+
additionalNodes: [
|
|
533
|
+
{
|
|
534
|
+
tag: 'meta',
|
|
535
|
+
attrs: { appdata: 'default' }
|
|
536
|
+
}
|
|
537
|
+
]
|
|
559
538
|
})
|
|
560
|
-
|
|
539
|
+
|
|
561
540
|
return msgId
|
|
562
541
|
}
|
|
563
542
|
|
|
564
|
-
const createParticipantNodes = async (
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
if (!Array.isArray(patched)) {
|
|
568
|
-
patched = jids ? jids.map(jid => ({ recipientJid: jid, ...patched })) : [patched]
|
|
543
|
+
const createParticipantNodes = async (recipientJids, message, extraAttrs, dsmMessage) => {
|
|
544
|
+
if (!recipientJids.length) {
|
|
545
|
+
return { nodes: [], shouldIncludeDeviceIdentity: false }
|
|
569
546
|
}
|
|
570
547
|
|
|
548
|
+
const patched = await patchMessageBeforeSending(message, recipientJids)
|
|
549
|
+
const patchedMessages = Array.isArray(patched)
|
|
550
|
+
? patched
|
|
551
|
+
: recipientJids.map(jid => ({ recipientJid: jid, message: patched }))
|
|
552
|
+
|
|
571
553
|
let shouldIncludeDeviceIdentity = false
|
|
572
554
|
|
|
573
555
|
const meId = authState.creds.me.id
|
|
574
556
|
const meLid = authState.creds.me?.lid
|
|
575
|
-
const meLidUser = meLid ?
|
|
576
|
-
const
|
|
577
|
-
|
|
578
|
-
for (const patchedMessageWithJid of patched) {
|
|
579
|
-
const { recipientJid: wireJid, ...patchedMessage } = patchedMessageWithJid
|
|
580
|
-
if (!wireJid)
|
|
581
|
-
continue
|
|
557
|
+
const meLidUser = meLid ? jidDecode(meLid)?.user : null
|
|
558
|
+
const encryptionPromises = patchedMessages.map(async ({ recipientJid: jid, message: patchedMessage }) => {
|
|
559
|
+
if (!jid) return null
|
|
582
560
|
|
|
583
|
-
|
|
584
|
-
const decoded = WABinary_1.jidDecode(wireJid)
|
|
585
|
-
const user = decoded?.user
|
|
561
|
+
let msgToEncrypt = patchedMessage
|
|
586
562
|
|
|
587
|
-
if (
|
|
588
|
-
|
|
563
|
+
if (dsmMessage) {
|
|
564
|
+
const { user: targetUser } = jidDecode(jid)
|
|
565
|
+
const { user: ownPnUser } = jidDecode(meId)
|
|
566
|
+
const ownLidUser = meLidUser
|
|
567
|
+
const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser)
|
|
568
|
+
const isExactSenderDevice = jid === meId || (meLid && jid === meLid)
|
|
589
569
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
devicesByUser.get(user).push({ recipientJid: wireJid, patchedMessage })
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// Process each user's devices sequentially, but different users in parallel
|
|
598
|
-
const userEncryptionPromises = Array.from(devicesByUser.entries()).map(([user, userDevices]) => encryptionMutex.mutex(user, async () => {
|
|
599
|
-
logger.debug({ user, deviceCount: userDevices.length }, 'Acquiring encryption lock for user devices');
|
|
600
|
-
const userNodes = []
|
|
601
|
-
|
|
602
|
-
// Helper to get encryption JID with LID migration
|
|
603
|
-
const getEncryptionJid = async (wireJid) => {
|
|
604
|
-
if (!WABinary_1.isJidUser(wireJid))
|
|
605
|
-
return wireJid
|
|
606
|
-
|
|
607
|
-
try {
|
|
608
|
-
const lidForPN = await signalRepository.lidMapping.getLIDForPN(wireJid)
|
|
609
|
-
|
|
610
|
-
if (!lidForPN?.includes('@lid'))
|
|
611
|
-
return wireJid
|
|
612
|
-
|
|
613
|
-
// Preserve device ID from original wire JID
|
|
614
|
-
const wireDecoded = WABinary_1.jidDecode(wireJid)
|
|
615
|
-
const deviceId = wireDecoded?.device || 0
|
|
616
|
-
const lidDecoded = WABinary_1.jidDecode(lidForPN)
|
|
617
|
-
const lidWithDevice = WABinary_1.jidEncode(lidDecoded?.user, 'lid', deviceId)
|
|
618
|
-
|
|
619
|
-
// Migrate session to LID for unified encryption layer
|
|
620
|
-
try {
|
|
621
|
-
const migrationResult = await signalRepository.migrateSession([wireJid], lidWithDevice)
|
|
622
|
-
const recipientUser = WABinary_1.jidNormalizedUser(wireJid)
|
|
623
|
-
const ownPnUser = WABinary_1.jidNormalizedUser(meId)
|
|
624
|
-
const isOwnDevice = recipientUser === ownPnUser
|
|
625
|
-
logger.info({ wireJid, lidWithDevice, isOwnDevice }, 'Migrated to LID encryption')
|
|
626
|
-
|
|
627
|
-
// Delete PN session after successful migration
|
|
628
|
-
try {
|
|
629
|
-
if (migrationResult.migrated) {
|
|
630
|
-
await signalRepository.deleteSession([wireJid])
|
|
631
|
-
logger.debug({ deletedPNSession: wireJid }, 'Deleted PN session')
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
catch (deleteError) {
|
|
635
|
-
logger.warn({ wireJid, error: deleteError }, 'Failed to delete PN session')
|
|
636
|
-
}
|
|
637
|
-
return lidWithDevice
|
|
638
|
-
}
|
|
639
|
-
catch (migrationError) {
|
|
640
|
-
logger.warn({ wireJid, error: migrationError }, 'Failed to migrate session')
|
|
641
|
-
return wireJid
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
catch (error) {
|
|
645
|
-
logger.debug({ wireJid, error }, 'Failed to check LID mapping')
|
|
646
|
-
return wireJid
|
|
570
|
+
if (isOwnUser && !isExactSenderDevice) {
|
|
571
|
+
msgToEncrypt = dsmMessage
|
|
572
|
+
logger.debug({ jid, targetUser }, 'Using DSM for own device')
|
|
647
573
|
}
|
|
648
574
|
}
|
|
649
575
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
let messageToEncrypt = patchedMessage
|
|
654
|
-
|
|
655
|
-
if (dsmMessage) {
|
|
656
|
-
const { user: targetUser } = WABinary_1.jidDecode(wireJid)
|
|
657
|
-
const { user: ownPnUser } = WABinary_1.jidDecode(meId)
|
|
658
|
-
const ownLidUser = meLidUser
|
|
659
|
-
|
|
660
|
-
// Check if this is our device (same user, different device)
|
|
661
|
-
const isOwnUser = targetUser === ownPnUser || (ownLidUser && targetUser === ownLidUser)
|
|
662
|
-
|
|
663
|
-
// Exclude exact sender device (whatsmeow: if jid == ownJID || jid == ownLID { continue })
|
|
664
|
-
const isExactSenderDevice = wireJid === meId || (authState.creds.me?.lid && wireJid === authState.creds.me.lid)
|
|
665
|
-
|
|
666
|
-
if (isOwnUser && !isExactSenderDevice) {
|
|
667
|
-
messageToEncrypt = dsmMessage
|
|
668
|
-
logger.debug({ wireJid, targetUser }, 'Using DSM for own device')
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
const bytes = Utils_1.encodeWAMessage(messageToEncrypt)
|
|
673
|
-
|
|
674
|
-
// Get encryption JID with LID migration
|
|
675
|
-
const encryptionJid = await getEncryptionJid(wireJid)
|
|
676
|
-
|
|
677
|
-
// ENCRYPT: Use the determined encryption identity (prefers migrated LID)
|
|
576
|
+
const bytes = encodeWAMessage(msgToEncrypt)
|
|
577
|
+
const mutexKey = jid
|
|
578
|
+
const node = await encryptionMutex.mutex(mutexKey, async () => {
|
|
678
579
|
const { type, ciphertext } = await signalRepository.encryptMessage({
|
|
679
|
-
jid
|
|
580
|
+
jid,
|
|
680
581
|
data: bytes
|
|
681
582
|
})
|
|
682
583
|
|
|
@@ -684,9 +585,9 @@ const makeMessagesSocket = (config) => {
|
|
|
684
585
|
shouldIncludeDeviceIdentity = true
|
|
685
586
|
}
|
|
686
587
|
|
|
687
|
-
|
|
588
|
+
return {
|
|
688
589
|
tag: 'to',
|
|
689
|
-
attrs: { jid
|
|
590
|
+
attrs: { jid },
|
|
690
591
|
content: [
|
|
691
592
|
{
|
|
692
593
|
tag: 'enc',
|
|
@@ -698,53 +599,71 @@ const makeMessagesSocket = (config) => {
|
|
|
698
599
|
content: ciphertext
|
|
699
600
|
}
|
|
700
601
|
]
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
602
|
+
};
|
|
603
|
+
})
|
|
604
|
+
|
|
605
|
+
return node
|
|
606
|
+
})
|
|
607
|
+
|
|
608
|
+
const nodes = (await Promise.all(encryptionPromises)).filter(node => node !== null)
|
|
707
609
|
|
|
708
|
-
// Wait for all users to complete (users are processed in parallel)
|
|
709
|
-
const userNodesArrays = await Promise.all(userEncryptionPromises)
|
|
710
|
-
const nodes = userNodesArrays.flat()
|
|
711
610
|
return { nodes, shouldIncludeDeviceIdentity }
|
|
712
611
|
}
|
|
612
|
+
|
|
613
|
+
/** Fetch image for groups, user, and newsletter **/
|
|
614
|
+
const profilePictureUrl = async (jid) => {
|
|
615
|
+
if (isJidNewsletter(jid)) {
|
|
616
|
+
const metadata = await suki.newsletterMetadata('JID', jid)
|
|
617
|
+
|
|
618
|
+
return getUrlFromDirectPath(metadata.thread_metadata.picture?.direct_path || '')
|
|
619
|
+
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
else {
|
|
623
|
+
const result = await query({
|
|
624
|
+
tag: 'iq',
|
|
625
|
+
attrs: {
|
|
626
|
+
target: jidNormalizedUser(jid),
|
|
627
|
+
to: S_WHATSAPP_NET,
|
|
628
|
+
type: 'get',
|
|
629
|
+
xmlns: 'w:profile:picture'
|
|
630
|
+
},
|
|
631
|
+
content: [{
|
|
632
|
+
tag: 'picture',
|
|
633
|
+
attrs: {
|
|
634
|
+
type: 'image',
|
|
635
|
+
query: 'url'
|
|
636
|
+
}
|
|
637
|
+
}]
|
|
638
|
+
})
|
|
639
|
+
|
|
640
|
+
const child = getBinaryNodeChild(result, 'picture')
|
|
641
|
+
|
|
642
|
+
return child?.attrs?.url || null
|
|
643
|
+
}
|
|
644
|
+
}
|
|
713
645
|
|
|
714
646
|
const relayMessage = async (jid, message, { messageId: msgId, participant, additionalAttributes, useUserDevicesCache, useCachedGroupMetadata, statusJidList, additionalNodes, AI = false }) => {
|
|
715
647
|
const meId = authState.creds.me.id
|
|
716
648
|
const meLid = authState.creds.me?.lid
|
|
717
|
-
|
|
649
|
+
const isRetryResend = Boolean(participant?.jid)
|
|
650
|
+
|
|
651
|
+
let shouldIncludeDeviceIdentity = isRetryResend
|
|
718
652
|
let didPushAdditional = false
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
const { user, server } = WABinary_1.jidDecode(jid)
|
|
722
|
-
|
|
653
|
+
|
|
723
654
|
const statusJid = 'status@broadcast'
|
|
655
|
+
const { user, server } = jidDecode(jid)
|
|
724
656
|
const isGroup = server === 'g.us'
|
|
725
|
-
const isPrivate = server === 's.whatsapp.net'
|
|
726
|
-
const isNewsletter = server == 'newsletter'
|
|
727
657
|
const isStatus = jid === statusJid
|
|
728
658
|
const isLid = server === 'lid'
|
|
729
|
-
|
|
730
|
-
|
|
659
|
+
const isNewsletter = server === 'newsletter'
|
|
660
|
+
const isGroupOrStatus = isGroup || isStatus
|
|
731
661
|
const finalJid = jid
|
|
732
662
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
if (isLid && meLid) {
|
|
737
|
-
ownId = meLid
|
|
738
|
-
logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation')
|
|
739
|
-
}
|
|
740
|
-
else {
|
|
741
|
-
logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation')
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
msgId = msgId || Utils_1.generateMessageID(authState.creds.me.id)
|
|
745
|
-
useUserDevicesCache = useUserDevicesCache !== false
|
|
663
|
+
msgId = msgId || generateMessageID(meId)
|
|
664
|
+
useUserDevicesCache = useUserDevicesCache !== false;
|
|
746
665
|
useCachedGroupMetadata = useCachedGroupMetadata !== false && !isStatus
|
|
747
|
-
|
|
666
|
+
|
|
748
667
|
const participants = []
|
|
749
668
|
const destinationJid = !isStatus ? finalJid : statusJid
|
|
750
669
|
const binaryNodeContent = []
|
|
@@ -755,33 +674,30 @@ const makeMessagesSocket = (config) => {
|
|
|
755
674
|
destinationJid,
|
|
756
675
|
message
|
|
757
676
|
},
|
|
758
|
-
messageContextInfo: message.messageContextInfo
|
|
677
|
+
messageContextInfo: message.messageContextInfo
|
|
759
678
|
}
|
|
760
679
|
|
|
761
680
|
const extraAttrs = {}
|
|
762
681
|
|
|
763
682
|
const regexGroupOld = /^(\d{1,15})-(\d+)@g\.us$/
|
|
764
683
|
|
|
765
|
-
const messages =
|
|
684
|
+
const messages = normalizeMessageContent(message)
|
|
766
685
|
|
|
767
686
|
const buttonType = getButtonType(messages)
|
|
768
687
|
const pollMessage = messages.pollCreationMessage || messages.pollCreationMessageV2 || messages.pollCreationMessageV3
|
|
769
688
|
|
|
770
689
|
|
|
771
690
|
if (participant) {
|
|
772
|
-
// when the retry request is not for a group
|
|
773
|
-
// only send to the specific device that asked for a retry
|
|
774
|
-
// otherwise the message is sent out to every device that should be a recipient
|
|
775
691
|
if (!isGroup && !isStatus) {
|
|
776
|
-
additionalAttributes = { ...additionalAttributes,
|
|
692
|
+
additionalAttributes = { ...additionalAttributes, device_fanout: 'false' }
|
|
777
693
|
}
|
|
778
|
-
|
|
779
|
-
const { user, device } =
|
|
780
|
-
|
|
694
|
+
|
|
695
|
+
const { user, device } = jidDecode(participant.jid)
|
|
696
|
+
|
|
781
697
|
devices.push({
|
|
782
698
|
user,
|
|
783
699
|
device,
|
|
784
|
-
|
|
700
|
+
jid: participant.jid
|
|
785
701
|
})
|
|
786
702
|
}
|
|
787
703
|
|
|
@@ -791,6 +707,34 @@ const makeMessagesSocket = (config) => {
|
|
|
791
707
|
if (mediaType) {
|
|
792
708
|
extraAttrs['mediatype'] = mediaType
|
|
793
709
|
}
|
|
710
|
+
|
|
711
|
+
if (isNewsletter) {
|
|
712
|
+
const patched = patchMessageBeforeSending ? await patchMessageBeforeSending(message, []) : message
|
|
713
|
+
const bytes = encodeNewsletterMessage(patched)
|
|
714
|
+
|
|
715
|
+
binaryNodeContent.push({
|
|
716
|
+
tag: 'plaintext',
|
|
717
|
+
attrs: {},
|
|
718
|
+
content: bytes
|
|
719
|
+
})
|
|
720
|
+
|
|
721
|
+
const stanza = {
|
|
722
|
+
tag: 'message',
|
|
723
|
+
attrs: {
|
|
724
|
+
to: jid,
|
|
725
|
+
id: msgId,
|
|
726
|
+
type: getTypeMessage(message),
|
|
727
|
+
...(additionalAttributes || {})
|
|
728
|
+
},
|
|
729
|
+
content: binaryNodeContent
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
logger.debug({ msgId }, `sending newsletter message to ${jid}`)
|
|
733
|
+
|
|
734
|
+
await sendNode(stanza)
|
|
735
|
+
|
|
736
|
+
return
|
|
737
|
+
}
|
|
794
738
|
|
|
795
739
|
if (messages.pinInChatMessage || messages.keepInChatMessage || message.reactionMessage || message.protocolMessage?.editedMessage) {
|
|
796
740
|
extraAttrs['decrypt-fail'] = 'hide'
|
|
@@ -800,244 +744,273 @@ const makeMessagesSocket = (config) => {
|
|
|
800
744
|
extraAttrs['native_flow_name'] = messages.interactiveResponseMessage.nativeFlowResponseMessage?.name || 'menu_options'
|
|
801
745
|
}
|
|
802
746
|
|
|
803
|
-
if (
|
|
747
|
+
if (isGroupOrStatus && !isRetryResend) {
|
|
804
748
|
const [groupData, senderKeyMap] = await Promise.all([
|
|
805
749
|
(async () => {
|
|
806
|
-
let groupData = useCachedGroupMetadata && cachedGroupMetadata ? await cachedGroupMetadata(jid) : undefined
|
|
807
|
-
|
|
750
|
+
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?
|
|
751
|
+
|
|
808
752
|
if (groupData && Array.isArray(groupData?.participants)) {
|
|
809
753
|
logger.trace({ jid, participants: groupData.participants.length }, 'using cached group metadata')
|
|
810
754
|
}
|
|
811
|
-
|
|
755
|
+
|
|
812
756
|
else if (!isStatus) {
|
|
813
|
-
groupData = await groupMetadata(jid)
|
|
757
|
+
groupData = await groupMetadata(jid) // TODO: start storing group participant list + addr mode in Signal & stop relying on this
|
|
814
758
|
}
|
|
815
|
-
|
|
759
|
+
|
|
816
760
|
return groupData
|
|
817
761
|
})(),
|
|
818
|
-
|
|
819
762
|
(async () => {
|
|
820
763
|
if (!participant && !isStatus) {
|
|
821
|
-
|
|
764
|
+
// what if sender memory is less accurate than the cached metadata
|
|
765
|
+
// on participant change in group, we should do sender memory manipulation
|
|
766
|
+
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?
|
|
767
|
+
|
|
822
768
|
return result[jid] || {}
|
|
823
769
|
}
|
|
824
|
-
|
|
770
|
+
|
|
825
771
|
return {}
|
|
826
|
-
|
|
827
772
|
})()
|
|
828
773
|
])
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
774
|
+
|
|
775
|
+
const participantsList = groupData ? groupData.participants.map(p => p.id) : []
|
|
776
|
+
|
|
777
|
+
if (groupData?.ephemeralDuration && groupData.ephemeralDuration > 0) {
|
|
778
|
+
additionalAttributes = {
|
|
779
|
+
...additionalAttributes,
|
|
780
|
+
expiration: groupData.ephemeralDuration.toString()
|
|
835
781
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
if (isStatus && statusJidList) {
|
|
785
|
+
participantsList.push(...statusJidList)
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false)
|
|
789
|
+
|
|
790
|
+
devices.push(...additionalDevices)
|
|
791
|
+
|
|
792
|
+
if (isGroup) {
|
|
793
|
+
additionalAttributes = {
|
|
794
|
+
...additionalAttributes,
|
|
795
|
+
addressing_mode: groupData?.addressingMode || 'lid'
|
|
843
796
|
}
|
|
844
|
-
|
|
845
|
-
const additionalDevices = await getUSyncDevices(participantsList, !!useUserDevicesCache, false)
|
|
846
|
-
devices.push(...additionalDevices)
|
|
847
797
|
}
|
|
848
|
-
|
|
849
|
-
const patched = await patchMessageBeforeSending(message, devices.map(d => WABinary_1.jidEncode(d.user, isLid ? 'lid' : 's.whatsapp.net', d.device)))
|
|
850
|
-
const bytes = Utils_1.encodeWAMessage(patched)
|
|
851
798
|
|
|
852
|
-
|
|
853
|
-
|
|
799
|
+
const patched = await patchMessageBeforeSending(message)
|
|
800
|
+
|
|
801
|
+
if (Array.isArray(patched)) {
|
|
802
|
+
throw new Boom('Per-jid patching is not supported in groups')
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
const bytes = encodeWAMessage(patched)
|
|
806
|
+
const groupAddressingMode = additionalAttributes?.['addressing_mode'] || groupData?.addressingMode || 'lid'
|
|
854
807
|
const groupSenderIdentity = groupAddressingMode === 'lid' && meLid ? meLid : meId
|
|
855
|
-
|
|
856
808
|
const { ciphertext, senderKeyDistributionMessage } = await signalRepository.encryptGroupMessage({
|
|
857
809
|
group: destinationJid,
|
|
858
810
|
data: bytes,
|
|
859
811
|
meId: groupSenderIdentity
|
|
860
812
|
})
|
|
861
|
-
|
|
862
|
-
const
|
|
863
|
-
|
|
864
|
-
// ensure a connection is established with every device
|
|
813
|
+
|
|
814
|
+
const senderKeyRecipients = []
|
|
815
|
+
|
|
865
816
|
for (const device of devices) {
|
|
866
|
-
|
|
867
|
-
const deviceJid = device.wireJid
|
|
817
|
+
const deviceJid = device.jid
|
|
868
818
|
const hasKey = !!senderKeyMap[deviceJid]
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
819
|
+
|
|
820
|
+
if ((!hasKey || !!participant) &&
|
|
821
|
+
!isHostedLidUser(deviceJid) &&
|
|
822
|
+
!isHostedPnUser(deviceJid) &&
|
|
823
|
+
device.device !== 99) {
|
|
824
|
+
//todo: revamp all this logic
|
|
825
|
+
// 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
|
|
826
|
+
senderKeyRecipients.push(deviceJid)
|
|
872
827
|
senderKeyMap[deviceJid] = true
|
|
873
828
|
}
|
|
874
829
|
}
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
logger.debug({ senderKeyJids }, 'sending new sender key')
|
|
830
|
+
|
|
831
|
+
if (senderKeyRecipients.length) {
|
|
832
|
+
logger.debug({ senderKeyJids: senderKeyRecipients }, 'sending new sender key')
|
|
833
|
+
|
|
880
834
|
const senderKeyMsg = {
|
|
881
835
|
senderKeyDistributionMessage: {
|
|
882
836
|
axolotlSenderKeyDistributionMessage: senderKeyDistributionMessage,
|
|
883
837
|
groupId: destinationJid
|
|
884
838
|
}
|
|
885
839
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
840
|
+
|
|
841
|
+
const senderKeySessionTargets = senderKeyRecipients
|
|
842
|
+
|
|
843
|
+
await assertSessions(senderKeySessionTargets)
|
|
844
|
+
|
|
845
|
+
const result = await createParticipantNodes(senderKeyRecipients, senderKeyMsg, extraAttrs)
|
|
846
|
+
|
|
847
|
+
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || result.shouldIncludeDeviceIdentity;
|
|
893
848
|
participants.push(...result.nodes)
|
|
894
849
|
}
|
|
895
|
-
|
|
850
|
+
|
|
896
851
|
binaryNodeContent.push({
|
|
897
852
|
tag: 'enc',
|
|
898
|
-
attrs: { v: '2', type: 'skmsg', ...extraAttrs },
|
|
853
|
+
attrs: { v: '2', type: 'skmsg', ...extraAttrs },
|
|
899
854
|
content: ciphertext
|
|
900
855
|
})
|
|
901
|
-
|
|
856
|
+
|
|
902
857
|
await authState.keys.set({ 'sender-key-memory': { [jid]: senderKeyMap } })
|
|
903
858
|
}
|
|
904
859
|
|
|
905
|
-
else
|
|
906
|
-
//
|
|
907
|
-
if
|
|
908
|
-
|
|
909
|
-
|
|
860
|
+
else {
|
|
861
|
+
// ADDRESSING CONSISTENCY: Match own identity to conversation context
|
|
862
|
+
// TODO: investigate if this is true
|
|
863
|
+
let ownId = meId
|
|
864
|
+
|
|
865
|
+
if (isLid && meLid) {
|
|
866
|
+
ownId = meLid;
|
|
867
|
+
logger.debug({ to: jid, ownId }, 'Using LID identity for @lid conversation')
|
|
910
868
|
}
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
msgId = message.protocolMessage.key?.id
|
|
915
|
-
message = {}
|
|
869
|
+
|
|
870
|
+
else {
|
|
871
|
+
logger.debug({ to: jid, ownId }, 'Using PN identity for @s.whatsapp.net conversation')
|
|
916
872
|
}
|
|
917
|
-
|
|
918
|
-
const
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
binaryNodeContent.push({
|
|
922
|
-
tag: 'plaintext',
|
|
923
|
-
attrs: extraAttrs,
|
|
924
|
-
content: bytes
|
|
925
|
-
})
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
else {
|
|
929
|
-
const { user: ownUser } = WABinary_1.jidDecode(ownId)
|
|
930
|
-
|
|
931
|
-
if (!participant) {
|
|
873
|
+
|
|
874
|
+
const { user: ownUser } = jidDecode(ownId)
|
|
875
|
+
|
|
876
|
+
if (!isRetryResend) {
|
|
932
877
|
const targetUserServer = isLid ? 'lid' : 's.whatsapp.net'
|
|
878
|
+
|
|
933
879
|
devices.push({
|
|
934
880
|
user,
|
|
935
881
|
device: 0,
|
|
936
|
-
|
|
882
|
+
jid: jidEncode(user, targetUserServer, 0) // rajeh, todo: this entire logic is convoluted and weird.
|
|
937
883
|
})
|
|
938
884
|
|
|
939
|
-
// Own user matches conversation addressing mode
|
|
940
885
|
if (user !== ownUser) {
|
|
941
|
-
const ownUserServer = isLid ? 'lid' : 's.whatsapp.net'
|
|
942
|
-
const ownUserForAddressing = isLid && meLid ?
|
|
886
|
+
const ownUserServer = isLid ? 'lid' : 's.whatsapp.net'
|
|
887
|
+
const ownUserForAddressing = isLid && meLid ? jidDecode(meLid).user : jidDecode(meId).user
|
|
888
|
+
|
|
943
889
|
devices.push({
|
|
944
890
|
user: ownUserForAddressing,
|
|
945
891
|
device: 0,
|
|
946
|
-
|
|
892
|
+
jid: jidEncode(ownUserForAddressing, ownUserServer, 0)
|
|
947
893
|
})
|
|
948
894
|
}
|
|
949
|
-
|
|
895
|
+
|
|
950
896
|
if (additionalAttributes?.['category'] !== 'peer') {
|
|
951
897
|
// Clear placeholders and enumerate actual devices
|
|
952
898
|
devices.length = 0
|
|
953
899
|
|
|
954
900
|
// Use conversation-appropriate sender identity
|
|
955
901
|
const senderIdentity = isLid && meLid
|
|
956
|
-
?
|
|
957
|
-
:
|
|
958
|
-
|
|
902
|
+
? jidEncode(jidDecode(meLid)?.user, 'lid', undefined)
|
|
903
|
+
: jidEncode(jidDecode(meId)?.user, 's.whatsapp.net', undefined)
|
|
959
904
|
// Enumerate devices for sender and target with consistent addressing
|
|
960
|
-
const sessionDevices = await getUSyncDevices([senderIdentity, jid],
|
|
905
|
+
const sessionDevices = await getUSyncDevices([senderIdentity, jid], true, false)
|
|
906
|
+
|
|
961
907
|
devices.push(...sessionDevices)
|
|
908
|
+
|
|
962
909
|
logger.debug({
|
|
963
910
|
deviceCount: devices.length,
|
|
964
|
-
devices: devices.map(d => `${d.user}:${d.device}@${
|
|
911
|
+
devices: devices.map(d => `${d.user}:${d.device}@${jidDecode(d.jid)?.server}`)
|
|
965
912
|
}, 'Device enumeration complete with unified addressing')
|
|
966
913
|
}
|
|
967
914
|
}
|
|
968
|
-
|
|
969
|
-
const allJids = []
|
|
970
|
-
const meJids = []
|
|
971
|
-
const otherJids = []
|
|
972
915
|
|
|
973
|
-
const
|
|
974
|
-
const
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
916
|
+
const allRecipients = []
|
|
917
|
+
const meRecipients = []
|
|
918
|
+
const otherRecipients = []
|
|
919
|
+
|
|
920
|
+
const { user: mePnUser } = jidDecode(meId)
|
|
921
|
+
const { user: meLidUser } = meLid ? jidDecode(meLid) : { user: null }
|
|
922
|
+
|
|
923
|
+
for (const { user, jid } of devices) {
|
|
924
|
+
const isExactSenderDevice = jid === meId || (meLid && jid === meLid)
|
|
925
|
+
|
|
978
926
|
if (isExactSenderDevice) {
|
|
979
|
-
logger.debug({
|
|
927
|
+
logger.debug({ jid, meId, meLid }, 'Skipping exact sender device (whatsmeow pattern)')
|
|
980
928
|
continue
|
|
981
929
|
}
|
|
982
930
|
|
|
983
931
|
// Check if this is our device (could match either PN or LID user)
|
|
984
|
-
const isMe = user === mePnUser ||
|
|
985
|
-
|
|
986
|
-
|
|
932
|
+
const isMe = user === mePnUser || user === meLidUser
|
|
933
|
+
|
|
987
934
|
if (isMe) {
|
|
988
|
-
|
|
935
|
+
meRecipients.push(jid);
|
|
989
936
|
}
|
|
990
|
-
|
|
937
|
+
|
|
991
938
|
else {
|
|
992
|
-
|
|
939
|
+
otherRecipients.push(jid)
|
|
993
940
|
}
|
|
994
|
-
|
|
995
|
-
|
|
941
|
+
|
|
942
|
+
allRecipients.push(jid)
|
|
996
943
|
}
|
|
997
|
-
|
|
998
|
-
await assertSessions(
|
|
999
|
-
|
|
944
|
+
|
|
945
|
+
await assertSessions(allRecipients)
|
|
946
|
+
|
|
1000
947
|
const [{ nodes: meNodes, shouldIncludeDeviceIdentity: s1 }, { nodes: otherNodes, shouldIncludeDeviceIdentity: s2 }] = await Promise.all([
|
|
1001
948
|
// For own devices: use DSM if available (1:1 chats only)
|
|
1002
|
-
createParticipantNodes(
|
|
1003
|
-
createParticipantNodes(
|
|
949
|
+
createParticipantNodes(meRecipients, meMsg || message, extraAttrs),
|
|
950
|
+
createParticipantNodes(otherRecipients, message, extraAttrs, meMsg)
|
|
1004
951
|
])
|
|
1005
|
-
|
|
952
|
+
|
|
1006
953
|
participants.push(...meNodes)
|
|
1007
|
-
|
|
1008
954
|
participants.push(...otherNodes)
|
|
1009
955
|
|
|
1010
|
-
if (
|
|
1011
|
-
extraAttrs['phash'] =
|
|
956
|
+
if (meRecipients.length > 0 || otherRecipients.length > 0) {
|
|
957
|
+
extraAttrs['phash'] = generateParticipantHashV2([...meRecipients, ...otherRecipients])
|
|
1012
958
|
}
|
|
1013
|
-
|
|
959
|
+
|
|
1014
960
|
shouldIncludeDeviceIdentity = shouldIncludeDeviceIdentity || s1 || s2
|
|
1015
961
|
}
|
|
1016
|
-
|
|
962
|
+
|
|
963
|
+
if (isRetryResend) {
|
|
964
|
+
const isParticipantLid = isLidUser(participant.jid)
|
|
965
|
+
const isMe = areJidsSameUser(participant.jid, isParticipantLid ? meLid : meId)
|
|
966
|
+
const encodedMessageToSend = isMe
|
|
967
|
+
? encodeWAMessage({
|
|
968
|
+
deviceSentMessage: {
|
|
969
|
+
destinationJid,
|
|
970
|
+
message
|
|
971
|
+
}
|
|
972
|
+
})
|
|
973
|
+
: encodeWAMessage(message)
|
|
974
|
+
const { type, ciphertext: encryptedContent } = await signalRepository.encryptMessage({
|
|
975
|
+
data: encodedMessageToSend,
|
|
976
|
+
jid: participant.jid
|
|
977
|
+
})
|
|
978
|
+
|
|
979
|
+
binaryNodeContent.push({
|
|
980
|
+
tag: 'enc',
|
|
981
|
+
attrs: {
|
|
982
|
+
v: '2',
|
|
983
|
+
type,
|
|
984
|
+
count: participant.count.toString()
|
|
985
|
+
},
|
|
986
|
+
content: encryptedContent
|
|
987
|
+
})
|
|
988
|
+
}
|
|
989
|
+
|
|
1017
990
|
if (participants.length) {
|
|
1018
991
|
if (additionalAttributes?.['category'] === 'peer') {
|
|
1019
992
|
const peerNode = participants[0]?.content?.[0]
|
|
1020
|
-
|
|
993
|
+
|
|
1021
994
|
if (peerNode) {
|
|
1022
995
|
binaryNodeContent.push(peerNode) // push only enc
|
|
1023
996
|
}
|
|
1024
997
|
}
|
|
1025
|
-
|
|
998
|
+
|
|
1026
999
|
else {
|
|
1027
1000
|
binaryNodeContent.push({
|
|
1028
1001
|
tag: 'participants',
|
|
1029
1002
|
attrs: {},
|
|
1030
1003
|
content: participants
|
|
1031
|
-
})
|
|
1004
|
+
});
|
|
1032
1005
|
}
|
|
1033
1006
|
}
|
|
1034
|
-
|
|
1007
|
+
|
|
1035
1008
|
const stanza = {
|
|
1036
1009
|
tag: 'message',
|
|
1037
1010
|
attrs: {
|
|
1011
|
+
id: msgId,
|
|
1038
1012
|
to: destinationJid,
|
|
1039
|
-
|
|
1040
|
-
type: getTypeMessage(message),
|
|
1013
|
+
type: getTypeMessage(message),
|
|
1041
1014
|
...(additionalAttributes || {})
|
|
1042
1015
|
},
|
|
1043
1016
|
content: binaryNodeContent
|
|
@@ -1047,34 +1020,45 @@ const makeMessagesSocket = (config) => {
|
|
|
1047
1020
|
// ensure the message is only sent to that person
|
|
1048
1021
|
// if a retry receipt is sent to everyone -- it'll fail decryption for everyone else who received the msg
|
|
1049
1022
|
if (participant) {
|
|
1050
|
-
if (
|
|
1023
|
+
if (isJidGroup(destinationJid)) {
|
|
1051
1024
|
stanza.attrs.to = destinationJid
|
|
1052
1025
|
stanza.attrs.participant = participant.jid
|
|
1053
1026
|
}
|
|
1054
|
-
|
|
1055
|
-
else if (
|
|
1027
|
+
|
|
1028
|
+
else if (areJidsSameUser(participant.jid, meId)) {
|
|
1056
1029
|
stanza.attrs.to = participant.jid
|
|
1057
1030
|
stanza.attrs.recipient = destinationJid
|
|
1058
1031
|
}
|
|
1059
|
-
|
|
1032
|
+
|
|
1060
1033
|
else {
|
|
1061
1034
|
stanza.attrs.to = participant.jid
|
|
1062
1035
|
}
|
|
1063
1036
|
}
|
|
1064
|
-
|
|
1037
|
+
|
|
1065
1038
|
else {
|
|
1066
1039
|
stanza.attrs.to = destinationJid
|
|
1067
1040
|
}
|
|
1068
|
-
|
|
1041
|
+
|
|
1069
1042
|
if (shouldIncludeDeviceIdentity) {
|
|
1070
1043
|
stanza.content.push({
|
|
1071
1044
|
tag: 'device-identity',
|
|
1072
1045
|
attrs: {},
|
|
1073
|
-
content:
|
|
1046
|
+
content: encodeSignedDeviceIdentity(authState.creds.account, true)
|
|
1074
1047
|
})
|
|
1075
|
-
|
|
1048
|
+
|
|
1076
1049
|
logger.debug({ jid }, 'adding device identity')
|
|
1077
1050
|
}
|
|
1051
|
+
|
|
1052
|
+
const contactTcTokenData = !isGroup && !isRetryResend && !isStatus ? await authState.keys.get('tctoken', [destinationJid]) : {}
|
|
1053
|
+
const tcTokenBuffer = contactTcTokenData[destinationJid]?.token
|
|
1054
|
+
|
|
1055
|
+
if (tcTokenBuffer) {
|
|
1056
|
+
stanza.content.push({
|
|
1057
|
+
tag: 'tctoken',
|
|
1058
|
+
attrs: {},
|
|
1059
|
+
content: tcTokenBuffer
|
|
1060
|
+
})
|
|
1061
|
+
}
|
|
1078
1062
|
|
|
1079
1063
|
if (isGroup && regexGroupOld.test(jid) && !message.reactionMessage) {
|
|
1080
1064
|
stanza.content.push({
|
|
@@ -1099,7 +1083,7 @@ const makeMessagesSocket = (config) => {
|
|
|
1099
1083
|
|
|
1100
1084
|
if (!isNewsletter && buttonType) {
|
|
1101
1085
|
const buttonsNode = getButtonArgs(messages)
|
|
1102
|
-
const filteredButtons =
|
|
1086
|
+
const filteredButtons = getBinaryFilteredButtons(additionalNodes ? additionalNodes : [])
|
|
1103
1087
|
|
|
1104
1088
|
if (filteredButtons) {
|
|
1105
1089
|
stanza.content.push(...additionalNodes)
|
|
@@ -1119,7 +1103,7 @@ const makeMessagesSocket = (config) => {
|
|
|
1119
1103
|
}
|
|
1120
1104
|
}
|
|
1121
1105
|
|
|
1122
|
-
const filteredBizBot =
|
|
1106
|
+
const filteredBizBot = getBinaryFilteredBizBot(additionalNodes ? additionalNodes : [])
|
|
1123
1107
|
|
|
1124
1108
|
if (filteredBizBot) {
|
|
1125
1109
|
stanza.content.push(...additionalNodes)
|
|
@@ -1149,7 +1133,7 @@ const makeMessagesSocket = (config) => {
|
|
|
1149
1133
|
}
|
|
1150
1134
|
|
|
1151
1135
|
const getTypeMessage = (msg) => {
|
|
1152
|
-
const message =
|
|
1136
|
+
const message = normalizeMessageContent(msg)
|
|
1153
1137
|
if (message.pollCreationMessage || message.pollCreationMessageV2 || message.pollCreationMessageV3) {
|
|
1154
1138
|
return 'poll'
|
|
1155
1139
|
}
|
|
@@ -1268,7 +1252,7 @@ const makeMessagesSocket = (config) => {
|
|
|
1268
1252
|
attrs: {
|
|
1269
1253
|
actual_actors: '2',
|
|
1270
1254
|
host_storage: '2',
|
|
1271
|
-
privacy_mode_ts:
|
|
1255
|
+
privacy_mode_ts: unixTimestampSeconds().toString()
|
|
1272
1256
|
},
|
|
1273
1257
|
content: [{
|
|
1274
1258
|
tag: 'interactive',
|
|
@@ -1298,7 +1282,7 @@ const makeMessagesSocket = (config) => {
|
|
|
1298
1282
|
attrs: {
|
|
1299
1283
|
actual_actors: '2',
|
|
1300
1284
|
host_storage: '2',
|
|
1301
|
-
privacy_mode_ts:
|
|
1285
|
+
privacy_mode_ts: unixTimestampSeconds().toString()
|
|
1302
1286
|
},
|
|
1303
1287
|
content: [{
|
|
1304
1288
|
tag: 'interactive',
|
|
@@ -1327,7 +1311,7 @@ const makeMessagesSocket = (config) => {
|
|
|
1327
1311
|
attrs: {
|
|
1328
1312
|
actual_actors: '2',
|
|
1329
1313
|
host_storage: '2',
|
|
1330
|
-
privacy_mode_ts:
|
|
1314
|
+
privacy_mode_ts: unixTimestampSeconds().toString()
|
|
1331
1315
|
},
|
|
1332
1316
|
content: [{
|
|
1333
1317
|
tag: 'list',
|
|
@@ -1349,19 +1333,19 @@ const makeMessagesSocket = (config) => {
|
|
|
1349
1333
|
attrs: {
|
|
1350
1334
|
actual_actors: '2',
|
|
1351
1335
|
host_storage: '2',
|
|
1352
|
-
privacy_mode_ts:
|
|
1336
|
+
privacy_mode_ts: unixTimestampSeconds().toString()
|
|
1353
1337
|
}
|
|
1354
1338
|
}
|
|
1355
1339
|
}
|
|
1356
1340
|
}
|
|
1357
1341
|
|
|
1358
1342
|
const getPrivacyTokens = async (jids) => {
|
|
1359
|
-
const t =
|
|
1343
|
+
const t = unixTimestampSeconds().toString()
|
|
1360
1344
|
|
|
1361
1345
|
const result = await query({
|
|
1362
1346
|
tag: 'iq',
|
|
1363
1347
|
attrs: {
|
|
1364
|
-
to:
|
|
1348
|
+
to: S_WHATSAPP_NET,
|
|
1365
1349
|
type: 'set',
|
|
1366
1350
|
xmlns: 'privacy'
|
|
1367
1351
|
},
|
|
@@ -1372,7 +1356,7 @@ const makeMessagesSocket = (config) => {
|
|
|
1372
1356
|
content: jids.map(jid => ({
|
|
1373
1357
|
tag: 'token',
|
|
1374
1358
|
attrs: {
|
|
1375
|
-
jid:
|
|
1359
|
+
jid: jidNormalizedUser(jid),
|
|
1376
1360
|
t,
|
|
1377
1361
|
type: 'trusted_contact'
|
|
1378
1362
|
}
|
|
@@ -1385,7 +1369,7 @@ const makeMessagesSocket = (config) => {
|
|
|
1385
1369
|
}
|
|
1386
1370
|
|
|
1387
1371
|
const getEphemeralGroup = (jid) => {
|
|
1388
|
-
if (!
|
|
1372
|
+
if (!isJidGroup(jid)) throw new TypeError("Jid should originate from a group!")
|
|
1389
1373
|
|
|
1390
1374
|
return groupQuery(jid, 'get', [{
|
|
1391
1375
|
tag: 'query',
|
|
@@ -1393,23 +1377,23 @@ const makeMessagesSocket = (config) => {
|
|
|
1393
1377
|
request: 'interactive'
|
|
1394
1378
|
}
|
|
1395
1379
|
}])
|
|
1396
|
-
.then((groups) =>
|
|
1397
|
-
.then((metadata) =>
|
|
1380
|
+
.then((groups) => getBinaryNodeChild(groups, 'group'))
|
|
1381
|
+
.then((metadata) => getBinaryNodeChild(metadata, 'ephemeral')?.attrs?.expiration || 0)
|
|
1398
1382
|
}
|
|
1399
1383
|
|
|
1400
|
-
const waUploadToServer =
|
|
1384
|
+
const waUploadToServer = getWAUploadToServer(config, refreshMediaConn)
|
|
1401
1385
|
|
|
1402
|
-
const waitForMsgMediaUpdate =
|
|
1386
|
+
const waitForMsgMediaUpdate = bindWaitForEvent(ev, 'messages.media-update')
|
|
1403
1387
|
|
|
1404
1388
|
return {
|
|
1405
1389
|
...suki,
|
|
1406
1390
|
getPrivacyTokens,
|
|
1407
1391
|
assertSessions,
|
|
1392
|
+
profilePictureUrl,
|
|
1408
1393
|
relayMessage,
|
|
1409
1394
|
sendReceipt,
|
|
1410
1395
|
sendReceipts,
|
|
1411
1396
|
readMessages,
|
|
1412
|
-
profilePictureUrl,
|
|
1413
1397
|
getUSyncDevices,
|
|
1414
1398
|
refreshMediaConn,
|
|
1415
1399
|
waUploadToServer,
|
|
@@ -1418,78 +1402,80 @@ const makeMessagesSocket = (config) => {
|
|
|
1418
1402
|
messageRetryManager,
|
|
1419
1403
|
createParticipantNodes,
|
|
1420
1404
|
sendPeerDataOperationMessage,
|
|
1405
|
+
updateMemberLabel,
|
|
1421
1406
|
updateMediaMessage: async (message) => {
|
|
1422
|
-
const content =
|
|
1407
|
+
const content = assertMediaContent(message.message)
|
|
1423
1408
|
const mediaKey = content.mediaKey
|
|
1424
1409
|
const meId = authState.creds.me.id
|
|
1425
|
-
const node = await
|
|
1410
|
+
const node = await encryptMediaRetryRequest(message.key, mediaKey, meId)
|
|
1411
|
+
|
|
1426
1412
|
let error = undefined
|
|
1427
|
-
|
|
1413
|
+
|
|
1428
1414
|
await Promise.all([
|
|
1429
1415
|
sendNode(node),
|
|
1430
1416
|
waitForMsgMediaUpdate(async (update) => {
|
|
1431
1417
|
const result = update.find(c => c.key.id === message.key.id)
|
|
1418
|
+
|
|
1432
1419
|
if (result) {
|
|
1433
1420
|
if (result.error) {
|
|
1434
1421
|
error = result.error
|
|
1435
1422
|
}
|
|
1436
|
-
|
|
1423
|
+
|
|
1437
1424
|
else {
|
|
1438
1425
|
try {
|
|
1439
|
-
const media = await
|
|
1440
|
-
|
|
1441
|
-
if (media.result !==
|
|
1442
|
-
const resultStr =
|
|
1443
|
-
|
|
1444
|
-
throw new
|
|
1426
|
+
const media = await decryptMediaRetryData(result.media, mediaKey, result.key.id)
|
|
1427
|
+
|
|
1428
|
+
if (media.result !== proto.MediaRetryNotification.ResultType.SUCCESS) {
|
|
1429
|
+
const resultStr = proto.MediaRetryNotification.ResultType[media.result]
|
|
1430
|
+
|
|
1431
|
+
throw new Boom(`Media re-upload failed by device (${resultStr})`, {
|
|
1432
|
+
data: media,
|
|
1433
|
+
statusCode: getStatusCodeForMediaRetry(media.result) || 404
|
|
1434
|
+
})
|
|
1445
1435
|
}
|
|
1446
|
-
|
|
1436
|
+
|
|
1447
1437
|
content.directPath = media.directPath
|
|
1448
|
-
|
|
1449
|
-
content.url = Utils_1.getUrlFromDirectPath(content.directPath)
|
|
1450
|
-
|
|
1438
|
+
content.url = getUrlFromDirectPath(content.directPath)
|
|
1451
1439
|
logger.debug({ directPath: media.directPath, key: result.key }, 'media update successful')
|
|
1452
1440
|
}
|
|
1453
|
-
|
|
1441
|
+
|
|
1454
1442
|
catch (err) {
|
|
1455
1443
|
error = err
|
|
1456
1444
|
}
|
|
1457
1445
|
}
|
|
1458
|
-
|
|
1446
|
+
|
|
1459
1447
|
return true
|
|
1460
1448
|
}
|
|
1461
1449
|
})
|
|
1462
1450
|
])
|
|
1463
|
-
|
|
1451
|
+
|
|
1464
1452
|
if (error) {
|
|
1465
1453
|
throw error
|
|
1466
1454
|
}
|
|
1467
|
-
|
|
1468
|
-
ev.emit('messages.update', [
|
|
1469
|
-
|
|
1470
|
-
])
|
|
1471
|
-
|
|
1455
|
+
|
|
1456
|
+
ev.emit('messages.update', [{ key: message.key, update: { message: message.message } }])
|
|
1457
|
+
|
|
1472
1458
|
return message
|
|
1473
1459
|
},
|
|
1474
1460
|
sendStatusMentions: async (content, jids = []) => {
|
|
1475
|
-
const userJid =
|
|
1461
|
+
const userJid = jidNormalizedUser(authState.creds.me.id)
|
|
1476
1462
|
let allUsers = new Set()
|
|
1477
1463
|
allUsers.add(userJid)
|
|
1478
1464
|
|
|
1479
1465
|
for (const id of jids) {
|
|
1480
|
-
const isGroup =
|
|
1481
|
-
const isPrivate =
|
|
1466
|
+
const isGroup = isJidGroup(id)
|
|
1467
|
+
const isPrivate = isPnUser(id)
|
|
1482
1468
|
|
|
1483
1469
|
if (isGroup) {
|
|
1484
1470
|
try {
|
|
1485
1471
|
const metadata = await cachedGroupMetadata(id) || await groupMetadata(id)
|
|
1486
|
-
const participants = metadata.participants.map(p =>
|
|
1472
|
+
const participants = metadata.participants.map(p => jidNormalizedUser(p.id))
|
|
1487
1473
|
participants.forEach(jid => allUsers.add(jid))
|
|
1488
1474
|
} catch (error) {
|
|
1489
1475
|
logger.error(`Error getting metadata for group ${id}: ${error}`)
|
|
1490
1476
|
}
|
|
1491
1477
|
} else if (isPrivate) {
|
|
1492
|
-
allUsers.add(
|
|
1478
|
+
allUsers.add(jidNormalizedUser(id))
|
|
1493
1479
|
}
|
|
1494
1480
|
}
|
|
1495
1481
|
|
|
@@ -1529,12 +1515,15 @@ const makeMessagesSocket = (config) => {
|
|
|
1529
1515
|
let msg
|
|
1530
1516
|
let mediaHandle
|
|
1531
1517
|
try {
|
|
1532
|
-
msg = await
|
|
1518
|
+
msg = await generateWAMessage(STORIES_JID, messageContent, {
|
|
1533
1519
|
logger,
|
|
1534
1520
|
userJid,
|
|
1535
|
-
getUrlInfo: text =>
|
|
1521
|
+
getUrlInfo: text => getUrlInfo(text, {
|
|
1536
1522
|
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
1537
|
-
fetchOpts: {
|
|
1523
|
+
fetchOpts: {
|
|
1524
|
+
timeout: 3000,
|
|
1525
|
+
...(httpRequestOptions || {})
|
|
1526
|
+
},
|
|
1538
1527
|
logger,
|
|
1539
1528
|
uploadImage: generateHighQualityLinkPreview ? waUploadToServer : undefined
|
|
1540
1529
|
}),
|
|
@@ -1555,7 +1544,7 @@ const makeMessagesSocket = (config) => {
|
|
|
1555
1544
|
throw error
|
|
1556
1545
|
}
|
|
1557
1546
|
|
|
1558
|
-
await relayMessage(
|
|
1547
|
+
await relayMessage(STORIES_JID, msg.message, {
|
|
1559
1548
|
messageId: msg.key.id,
|
|
1560
1549
|
statusJidList: uniqueUsers,
|
|
1561
1550
|
additionalNodes: [
|
|
@@ -1568,7 +1557,7 @@ const makeMessagesSocket = (config) => {
|
|
|
1568
1557
|
attrs: {},
|
|
1569
1558
|
content: jids.map(jid => ({
|
|
1570
1559
|
tag: 'to',
|
|
1571
|
-
attrs: { jid:
|
|
1560
|
+
attrs: { jid: jidNormalizedUser(jid) }
|
|
1572
1561
|
}))
|
|
1573
1562
|
}]
|
|
1574
1563
|
}]
|
|
@@ -1576,8 +1565,8 @@ const makeMessagesSocket = (config) => {
|
|
|
1576
1565
|
|
|
1577
1566
|
for (const id of jids) {
|
|
1578
1567
|
try {
|
|
1579
|
-
const normalizedId =
|
|
1580
|
-
const isPrivate =
|
|
1568
|
+
const normalizedId = jidNormalizedUser(id)
|
|
1569
|
+
const isPrivate = isPnUser(normalizedId)
|
|
1581
1570
|
const type = isPrivate ? 'statusMentionMessage' : 'groupStatusMentionMessage'
|
|
1582
1571
|
|
|
1583
1572
|
const protocolMessage = {
|
|
@@ -1590,11 +1579,11 @@ const makeMessagesSocket = (config) => {
|
|
|
1590
1579
|
}
|
|
1591
1580
|
},
|
|
1592
1581
|
messageContextInfo: {
|
|
1593
|
-
messageSecret:
|
|
1582
|
+
messageSecret: randomBytes(32)
|
|
1594
1583
|
}
|
|
1595
1584
|
}
|
|
1596
1585
|
|
|
1597
|
-
const statusMsg = await
|
|
1586
|
+
const statusMsg = await generateWAMessageFromContent(normalizedId,
|
|
1598
1587
|
protocolMessage,
|
|
1599
1588
|
{}
|
|
1600
1589
|
)
|
|
@@ -1612,7 +1601,7 @@ const makeMessagesSocket = (config) => {
|
|
|
1612
1601
|
}
|
|
1613
1602
|
)
|
|
1614
1603
|
|
|
1615
|
-
await
|
|
1604
|
+
await delay(2000)
|
|
1616
1605
|
} catch (error) {
|
|
1617
1606
|
logger.error(`Error sending to ${id}: ${error}`)
|
|
1618
1607
|
}
|
|
@@ -1625,7 +1614,7 @@ const makeMessagesSocket = (config) => {
|
|
|
1625
1614
|
const additionalAttributes = {}
|
|
1626
1615
|
|
|
1627
1616
|
if (!options.ephemeralExpiration) {
|
|
1628
|
-
if (
|
|
1617
|
+
if (isJidGroup(jid)) {
|
|
1629
1618
|
const expiration = await getEphemeralGroup(jid)
|
|
1630
1619
|
options.ephemeralExpiration = expiration
|
|
1631
1620
|
}
|
|
@@ -1634,19 +1623,19 @@ const makeMessagesSocket = (config) => {
|
|
|
1634
1623
|
if (typeof content === 'object' &&
|
|
1635
1624
|
'disappearingMessagesInChat' in content &&
|
|
1636
1625
|
typeof content['disappearingMessagesInChat'] !== 'undefined' &&
|
|
1637
|
-
|
|
1626
|
+
isJidGroup(jid)) {
|
|
1638
1627
|
|
|
1639
1628
|
const { disappearingMessagesInChat } = content
|
|
1640
1629
|
|
|
1641
1630
|
const value = typeof disappearingMessagesInChat === 'boolean' ?
|
|
1642
|
-
(disappearingMessagesInChat ?
|
|
1631
|
+
(disappearingMessagesInChat ? WA_DEFAULT_EPHEMERAL : 0) :
|
|
1643
1632
|
disappearingMessagesInChat
|
|
1644
1633
|
|
|
1645
1634
|
await groupToggleEphemeral(jid, value)
|
|
1646
1635
|
}
|
|
1647
1636
|
|
|
1648
1637
|
else if (typeof content === 'object' && 'album' in content && content.album) {
|
|
1649
|
-
const albumMsg = await
|
|
1638
|
+
const albumMsg = await prepareAlbumMessageContent(jid, content.album, {
|
|
1650
1639
|
suki: {
|
|
1651
1640
|
relayMessage,
|
|
1652
1641
|
waUploadToServer
|
|
@@ -1656,7 +1645,7 @@ const makeMessagesSocket = (config) => {
|
|
|
1656
1645
|
})
|
|
1657
1646
|
|
|
1658
1647
|
for (const media of albumMsg) {
|
|
1659
|
-
await
|
|
1648
|
+
await delay(options.delay || 500)
|
|
1660
1649
|
await relayMessage(jid, media.message, { messageId: media.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, additionalAttributes, statusJidList: options.statusJidList, additionalNodes: options.additionalNodes, AI: options.ai })
|
|
1661
1650
|
}
|
|
1662
1651
|
|
|
@@ -1666,14 +1655,14 @@ const makeMessagesSocket = (config) => {
|
|
|
1666
1655
|
else {
|
|
1667
1656
|
let mediaHandle
|
|
1668
1657
|
|
|
1669
|
-
const fullMsg = await
|
|
1658
|
+
const fullMsg = await generateWAMessage(jid, content, {
|
|
1670
1659
|
logger,
|
|
1671
1660
|
userJid,
|
|
1672
|
-
getUrlInfo: text =>
|
|
1661
|
+
getUrlInfo: text => getUrlInfo(text, {
|
|
1673
1662
|
thumbnailWidth: linkPreviewImageThumbnailWidth,
|
|
1674
1663
|
fetchOpts: {
|
|
1675
|
-
|
|
1676
|
-
...
|
|
1664
|
+
timeout: 3000,
|
|
1665
|
+
...(httpRequestOptions || {})
|
|
1677
1666
|
},
|
|
1678
1667
|
logger,
|
|
1679
1668
|
uploadImage: generateHighQualityLinkPreview
|
|
@@ -1683,13 +1672,13 @@ const makeMessagesSocket = (config) => {
|
|
|
1683
1672
|
getProfilePicUrl: profilePictureUrl,
|
|
1684
1673
|
getCallLink: createCallLink,
|
|
1685
1674
|
upload: async (encFilePath, opts) => {
|
|
1686
|
-
const up = await waUploadToServer(encFilePath, { ...opts, newsletter:
|
|
1675
|
+
const up = await waUploadToServer(encFilePath, { ...opts, newsletter: isJidNewsletter(jid) })
|
|
1687
1676
|
mediaHandle = up.handle
|
|
1688
1677
|
return up
|
|
1689
1678
|
},
|
|
1690
1679
|
mediaCache: config.mediaCache,
|
|
1691
1680
|
options: config.options,
|
|
1692
|
-
messageId:
|
|
1681
|
+
messageId: generateMessageID(userJid),
|
|
1693
1682
|
...options,
|
|
1694
1683
|
})
|
|
1695
1684
|
|
|
@@ -1700,7 +1689,7 @@ const makeMessagesSocket = (config) => {
|
|
|
1700
1689
|
|
|
1701
1690
|
if (isDelete || isKeep) {
|
|
1702
1691
|
// if the chat is a group, and I am not the author, then delete the message as an admin
|
|
1703
|
-
if (
|
|
1692
|
+
if (isJidGroup(content.delete?.remoteJid) && !content.delete?.fromMe || isJidNewsletter(jid)) {
|
|
1704
1693
|
additionalAttributes.edit = '8'
|
|
1705
1694
|
}
|
|
1706
1695
|
|
|
@@ -1710,7 +1699,7 @@ const makeMessagesSocket = (config) => {
|
|
|
1710
1699
|
}
|
|
1711
1700
|
|
|
1712
1701
|
else if (isEdit) {
|
|
1713
|
-
additionalAttributes.edit =
|
|
1702
|
+
additionalAttributes.edit = isJidNewsletter(jid) ? '3' : '1'
|
|
1714
1703
|
}
|
|
1715
1704
|
|
|
1716
1705
|
else if (isPin) {
|
|
@@ -1728,8 +1717,8 @@ const makeMessagesSocket = (config) => {
|
|
|
1728
1717
|
await relayMessage(jid, fullMsg.message, { messageId: fullMsg.key.id, useCachedGroupMetadata: options.useCachedGroupMetadata, additionalAttributes, statusJidList: options.statusJidList, additionalNodes: options.additionalNodes, AI: options.ai })
|
|
1729
1718
|
|
|
1730
1719
|
if (config.emitOwnEvents) {
|
|
1731
|
-
process.nextTick(() => {
|
|
1732
|
-
|
|
1720
|
+
process.nextTick(async () => {
|
|
1721
|
+
await messageMutex.mutex(() => upsertMessage(fullMsg, 'append'))
|
|
1733
1722
|
})
|
|
1734
1723
|
}
|
|
1735
1724
|
|