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