@hansaka02/baileys 7.3.4 → 7.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +203 -247
- package/lib/Defaults/baileys-version.json +2 -2
- package/lib/Defaults/connection.js +1 -1
- package/lib/Defaults/constants.js +13 -1
- package/lib/Defaults/history.js +3 -1
- package/lib/Signal/Group/sender-chain-key.js +1 -14
- package/lib/Signal/Group/sender-key-distribution-message.js +2 -2
- package/lib/Signal/Group/sender-key-record.js +2 -11
- package/lib/Signal/Group/sender-key-state.js +11 -57
- package/lib/Signal/libsignal.js +200 -116
- package/lib/Signal/lid-mapping.js +121 -68
- package/lib/Socket/Client/websocket.js +9 -2
- package/lib/Socket/business.js +5 -1
- package/lib/Socket/chats.js +180 -89
- package/lib/Socket/community.js +169 -41
- package/lib/Socket/groups.js +25 -21
- package/lib/Socket/messages-recv.js +458 -333
- package/lib/Socket/messages-send.js +517 -572
- package/lib/Socket/mex.js +61 -0
- package/lib/Socket/newsletter.js +159 -252
- package/lib/Socket/socket.js +283 -100
- package/lib/Types/Newsletter.js +32 -25
- package/lib/Utils/auth-utils.js +189 -354
- package/lib/Utils/browser-utils.js +43 -0
- package/lib/Utils/chat-utils.js +166 -41
- package/lib/Utils/decode-wa-message.js +77 -35
- package/lib/Utils/event-buffer.js +80 -24
- package/lib/Utils/generics.js +28 -128
- package/lib/Utils/history.js +10 -8
- package/lib/Utils/index.js +1 -1
- package/lib/Utils/link-preview.js +17 -32
- package/lib/Utils/lt-hash.js +28 -22
- package/lib/Utils/make-mutex.js +26 -28
- package/lib/Utils/message-retry-manager.js +51 -3
- package/lib/Utils/messages-media.js +343 -151
- package/lib/Utils/messages.js +806 -792
- package/lib/Utils/noise-handler.js +33 -2
- package/lib/Utils/pre-key-manager.js +126 -0
- package/lib/Utils/process-message.js +115 -55
- package/lib/Utils/signal.js +45 -18
- package/lib/Utils/validate-connection.js +52 -29
- package/lib/WABinary/constants.js +1268 -1268
- package/lib/WABinary/decode.js +58 -4
- package/lib/WABinary/encode.js +54 -7
- package/lib/WABinary/jid-utils.js +58 -11
- package/lib/WAM/constants.js +19064 -11563
- package/lib/WAM/encode.js +57 -8
- package/lib/WAUSync/USyncQuery.js +35 -19
- package/package.json +9 -8
- package/lib/Socket/usync.js +0 -83
|
@@ -25,35 +25,44 @@ const generateIV = (counter) => {
|
|
|
25
25
|
|
|
26
26
|
const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey }, NOISE_HEADER, logger, routingInfo }) => {
|
|
27
27
|
logger = logger.child({ class: 'ns' })
|
|
28
|
+
|
|
28
29
|
const authenticate = (data) => {
|
|
29
30
|
if (!isFinished) {
|
|
30
31
|
hash = sha256(Buffer.concat([hash, data]))
|
|
31
32
|
}
|
|
32
33
|
}
|
|
34
|
+
|
|
33
35
|
const encrypt = (plaintext) => {
|
|
34
36
|
const result = aesEncryptGCM(plaintext, encKey, generateIV(writeCounter), hash)
|
|
35
37
|
writeCounter += 1
|
|
36
38
|
authenticate(result)
|
|
37
39
|
return result
|
|
38
40
|
}
|
|
41
|
+
|
|
39
42
|
const decrypt = (ciphertext) => {
|
|
40
43
|
// before the handshake is finished, we use the same counter
|
|
41
44
|
// after handshake, the counters are different
|
|
42
45
|
const iv = generateIV(isFinished ? readCounter : writeCounter)
|
|
43
46
|
const result = aesDecryptGCM(ciphertext, decKey, iv, hash)
|
|
47
|
+
|
|
44
48
|
if (isFinished) {
|
|
45
49
|
readCounter += 1
|
|
46
50
|
}
|
|
51
|
+
|
|
47
52
|
else {
|
|
48
53
|
writeCounter += 1
|
|
49
54
|
}
|
|
55
|
+
|
|
50
56
|
authenticate(ciphertext)
|
|
57
|
+
|
|
51
58
|
return result
|
|
52
59
|
}
|
|
60
|
+
|
|
53
61
|
const localHKDF = async (data) => {
|
|
54
62
|
const key = await hkdf(Buffer.from(data), 64, { salt, info: '' })
|
|
55
63
|
return [key.slice(0, 32), key.slice(32)]
|
|
56
64
|
}
|
|
65
|
+
|
|
57
66
|
const mixIntoKey = async (data) => {
|
|
58
67
|
const [write, read] = await localHKDF(data)
|
|
59
68
|
salt = write
|
|
@@ -62,6 +71,7 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
|
|
|
62
71
|
readCounter = 0
|
|
63
72
|
writeCounter = 0
|
|
64
73
|
}
|
|
74
|
+
|
|
65
75
|
const finishInit = async () => {
|
|
66
76
|
const [write, read] = await localHKDF(new Uint8Array(0))
|
|
67
77
|
encKey = write
|
|
@@ -71,7 +81,9 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
|
|
|
71
81
|
writeCounter = 0
|
|
72
82
|
isFinished = true
|
|
73
83
|
}
|
|
84
|
+
|
|
74
85
|
const data = Buffer.from(NOISE_MODE)
|
|
86
|
+
|
|
75
87
|
let hash = data.byteLength === 32 ? data : sha256(data)
|
|
76
88
|
let salt = hash
|
|
77
89
|
let encKey = hash
|
|
@@ -81,8 +93,10 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
|
|
|
81
93
|
let isFinished = false
|
|
82
94
|
let sentIntro = false
|
|
83
95
|
let inBytes = Buffer.alloc(0)
|
|
96
|
+
|
|
84
97
|
authenticate(NOISE_HEADER)
|
|
85
98
|
authenticate(publicKey)
|
|
99
|
+
|
|
86
100
|
return {
|
|
87
101
|
encrypt,
|
|
88
102
|
decrypt,
|
|
@@ -95,20 +109,27 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
|
|
|
95
109
|
const decStaticContent = decrypt(serverHello.static)
|
|
96
110
|
await mixIntoKey(Curve.sharedKey(privateKey, decStaticContent))
|
|
97
111
|
const certDecoded = decrypt(serverHello.payload)
|
|
98
|
-
const { intermediate: certIntermediate } = proto.CertChain.decode(certDecoded)
|
|
112
|
+
const { intermediate: certIntermediate /*leaf*/ } = proto.CertChain.decode(certDecoded)
|
|
113
|
+
// TODO: handle this leaf stuff
|
|
99
114
|
const { issuerSerial } = proto.CertChain.NoiseCertificate.Details.decode(certIntermediate.details)
|
|
115
|
+
|
|
100
116
|
if (issuerSerial !== WA_CERT_DETAILS.SERIAL) {
|
|
101
117
|
throw new Boom('certification match failed', { statusCode: 400 })
|
|
102
118
|
}
|
|
119
|
+
|
|
103
120
|
const keyEnc = encrypt(noiseKey.public)
|
|
121
|
+
|
|
104
122
|
await mixIntoKey(Curve.sharedKey(noiseKey.private, serverHello.ephemeral))
|
|
123
|
+
|
|
105
124
|
return keyEnc
|
|
106
125
|
},
|
|
107
126
|
encodeFrame: (data) => {
|
|
108
127
|
if (isFinished) {
|
|
109
128
|
data = encrypt(data)
|
|
110
129
|
}
|
|
130
|
+
|
|
111
131
|
let header
|
|
132
|
+
|
|
112
133
|
if (routingInfo) {
|
|
113
134
|
header = Buffer.alloc(7)
|
|
114
135
|
header.write('ED', 0, 'utf8')
|
|
@@ -121,12 +142,15 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
|
|
|
121
142
|
else {
|
|
122
143
|
header = Buffer.from(NOISE_HEADER)
|
|
123
144
|
}
|
|
145
|
+
|
|
124
146
|
const introSize = sentIntro ? 0 : header.length
|
|
125
147
|
const frame = Buffer.alloc(introSize + 3 + data.byteLength)
|
|
148
|
+
|
|
126
149
|
if (!sentIntro) {
|
|
127
150
|
frame.set(header)
|
|
128
151
|
sentIntro = true
|
|
129
152
|
}
|
|
153
|
+
|
|
130
154
|
frame.writeUInt8(data.byteLength >> 16, introSize)
|
|
131
155
|
frame.writeUInt16BE(65535 & data.byteLength, introSize + 1)
|
|
132
156
|
frame.set(data, introSize + 3)
|
|
@@ -141,18 +165,25 @@ const makeNoiseHandler = ({ keyPair: { private: privateKey, public: publicKey },
|
|
|
141
165
|
return (inBytes.readUInt8() << 16) | inBytes.readUInt16BE(1)
|
|
142
166
|
}
|
|
143
167
|
}
|
|
168
|
+
|
|
144
169
|
inBytes = Buffer.concat([inBytes, newData])
|
|
145
170
|
logger.trace(`recv ${newData.length} bytes, total recv ${inBytes.length} bytes`)
|
|
171
|
+
|
|
146
172
|
let size = getBytesSize()
|
|
147
173
|
while (size && inBytes.length >= size + 3) {
|
|
148
174
|
let frame = inBytes.slice(3, size + 3)
|
|
149
|
-
|
|
175
|
+
|
|
176
|
+
inBytes = inBytes.slice(size + 3)
|
|
177
|
+
|
|
150
178
|
if (isFinished) {
|
|
151
179
|
const result = decrypt(frame)
|
|
152
180
|
frame = await decodeBinaryNode(result)
|
|
153
181
|
}
|
|
182
|
+
|
|
154
183
|
logger.trace({ msg: frame?.attrs?.id }, 'recv frame')
|
|
184
|
+
|
|
155
185
|
onFrame(frame)
|
|
186
|
+
|
|
156
187
|
size = getBytesSize()
|
|
157
188
|
}
|
|
158
189
|
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true })
|
|
4
|
+
|
|
5
|
+
const { default: PQueue } = require("p-queue")
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Manages pre-key operations with proper concurrency control
|
|
9
|
+
*/
|
|
10
|
+
class PreKeyManager {
|
|
11
|
+
constructor(store, logger) {
|
|
12
|
+
this.store = store
|
|
13
|
+
this.logger = logger
|
|
14
|
+
this.queues = new Map()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get or create a queue for a specific key type
|
|
19
|
+
*/
|
|
20
|
+
getQueue(keyType) {
|
|
21
|
+
if (!this.queues.has(keyType)) {
|
|
22
|
+
this.queues.set(keyType, new PQueue({ concurrency: 1 }))
|
|
23
|
+
}
|
|
24
|
+
return this.queues.get(keyType)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Process pre-key operations (updates and deletions)
|
|
29
|
+
*/
|
|
30
|
+
async processOperations(data, keyType, transactionCache, mutations, isInTransaction) {
|
|
31
|
+
const keyData = data[keyType]
|
|
32
|
+
|
|
33
|
+
if (!keyData) return
|
|
34
|
+
|
|
35
|
+
return this.getQueue(keyType).add(async () => {
|
|
36
|
+
// Ensure structures exist
|
|
37
|
+
transactionCache[keyType] = transactionCache[keyType] || {}
|
|
38
|
+
mutations[keyType] = mutations[keyType] || {}
|
|
39
|
+
|
|
40
|
+
// Separate deletions from updates
|
|
41
|
+
const deletions = []
|
|
42
|
+
const updates = {}
|
|
43
|
+
|
|
44
|
+
for (const keyId in keyData) {
|
|
45
|
+
if (keyData[keyId] === null) {
|
|
46
|
+
deletions.push(keyId)
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
updates[keyId] = keyData[keyId]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Process updates (no validation needed)
|
|
54
|
+
if (Object.keys(updates).length > 0) {
|
|
55
|
+
Object.assign(transactionCache[keyType], updates)
|
|
56
|
+
Object.assign(mutations[keyType], updates)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Process deletions with validation
|
|
60
|
+
if (deletions.length > 0) {
|
|
61
|
+
await this.processDeletions(keyType, deletions, transactionCache, mutations, isInTransaction)
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Process deletions with validation
|
|
68
|
+
*/
|
|
69
|
+
async processDeletions(keyType, ids, transactionCache, mutations, isInTransaction) {
|
|
70
|
+
if (isInTransaction) {
|
|
71
|
+
// In transaction, only allow deletion if key exists in cache
|
|
72
|
+
for (const keyId of ids) {
|
|
73
|
+
if (transactionCache[keyType]?.[keyId]) {
|
|
74
|
+
transactionCache[keyType][keyId] = null
|
|
75
|
+
mutations[keyType][keyId] = null
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
this.logger.warn(`Skipping deletion of non-existent ${keyType} in transaction: ${keyId}`)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Outside transaction, validate against store
|
|
84
|
+
const existingKeys = await this.store.get(keyType, ids)
|
|
85
|
+
for (const keyId of ids) {
|
|
86
|
+
if (existingKeys[keyId]) {
|
|
87
|
+
transactionCache[keyType][keyId] = null
|
|
88
|
+
mutations[keyType][keyId] = null
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
this.logger.warn(`Skipping deletion of non-existent ${keyType}: ${keyId}`)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Validate and process pre-key deletions outside transactions
|
|
99
|
+
*/
|
|
100
|
+
async validateDeletions(data, keyType) {
|
|
101
|
+
const keyData = data[keyType]
|
|
102
|
+
|
|
103
|
+
if (!keyData) return
|
|
104
|
+
|
|
105
|
+
return this.getQueue(keyType).add(async () => {
|
|
106
|
+
// Find all deletion requests
|
|
107
|
+
const deletionIds = Object.keys(keyData).filter(id => keyData[id] === null)
|
|
108
|
+
|
|
109
|
+
if (deletionIds.length === 0) return
|
|
110
|
+
|
|
111
|
+
// Validate deletions
|
|
112
|
+
const existingKeys = await this.store.get(keyType, deletionIds)
|
|
113
|
+
|
|
114
|
+
for (const keyId of deletionIds) {
|
|
115
|
+
if (!existingKeys[keyId]) {
|
|
116
|
+
this.logger.warn(`Skipping deletion of non-existent ${keyType}: ${keyId}`)
|
|
117
|
+
delete data[keyType][keyId]
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
module.exports = {
|
|
125
|
+
PreKeyManager
|
|
126
|
+
}
|
|
@@ -11,8 +11,13 @@ const {
|
|
|
11
11
|
} = require("../Utils")
|
|
12
12
|
const {
|
|
13
13
|
areJidsSameUser,
|
|
14
|
+
isHostedLidUser,
|
|
15
|
+
isHostedPnUser,
|
|
14
16
|
isJidBroadcast,
|
|
15
|
-
isJidStatusBroadcast,
|
|
17
|
+
isJidStatusBroadcast,
|
|
18
|
+
isLidUser,
|
|
19
|
+
jidDecode,
|
|
20
|
+
jidEncode,
|
|
16
21
|
jidNormalizedUser
|
|
17
22
|
} = require("../WABinary")
|
|
18
23
|
const {
|
|
@@ -37,18 +42,32 @@ const REAL_MSG_REQ_ME_STUB_TYPES = new Set([
|
|
|
37
42
|
])
|
|
38
43
|
|
|
39
44
|
/** Cleans a received message to further processing */
|
|
40
|
-
const cleanMessage = (message, meId) => {
|
|
45
|
+
const cleanMessage = (message, meId, meLid) => {
|
|
41
46
|
// ensure remoteJid and participant doesn't have device or agent in it
|
|
42
|
-
message.key.remoteJid
|
|
43
|
-
|
|
47
|
+
if (isHostedPnUser(message.key.remoteJid) || isHostedLidUser(message.key.remoteJid)) {
|
|
48
|
+
message.key.remoteJid = jidEncode(jidDecode(message.key?.remoteJid)?.user, isHostedPnUser(message.key.remoteJid) ? 's.whatsapp.net' : 'lid')
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
message.key.remoteJid = jidNormalizedUser(message.key.remoteJid)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (isHostedPnUser(message.key.participant) || isHostedLidUser(message.key.participant)) {
|
|
55
|
+
message.key.participant = jidEncode(jidDecode(message.key.participant)?.user, isHostedPnUser(message.key.participant) ? 's.whatsapp.net' : 'lid')
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
message.key.participant = jidNormalizedUser(message.key.participant)
|
|
59
|
+
}
|
|
44
60
|
const content = normalizeMessageContent(message.message)
|
|
61
|
+
|
|
45
62
|
// if the message has a reaction, ensure fromMe & remoteJid are from our perspective
|
|
46
63
|
if (content?.reactionMessage) {
|
|
47
64
|
normaliseKey(content.reactionMessage.key)
|
|
48
65
|
}
|
|
66
|
+
|
|
49
67
|
if (content?.pollUpdateMessage) {
|
|
50
68
|
normaliseKey(content.pollUpdateMessage.pollCreationMessageKey)
|
|
51
69
|
}
|
|
70
|
+
|
|
52
71
|
function normaliseKey(msgKey) {
|
|
53
72
|
// if the reaction is from another user
|
|
54
73
|
// we've to correctly map the key to this user's perspective
|
|
@@ -56,11 +75,13 @@ const cleanMessage = (message, meId) => {
|
|
|
56
75
|
// if the sender believed the message being reacted to is not from them
|
|
57
76
|
// we've to correct the key to be from them, or some other participant
|
|
58
77
|
msgKey.fromMe = !msgKey.fromMe
|
|
59
|
-
? areJidsSameUser(msgKey.participant || msgKey.remoteJid, meId)
|
|
60
|
-
|
|
61
|
-
//
|
|
62
|
-
|
|
78
|
+
? areJidsSameUser(msgKey.participant || msgKey.remoteJid, meId) ||
|
|
79
|
+
areJidsSameUser(msgKey.participant || msgKey.remoteJid, meLid)
|
|
80
|
+
: // if the message being reacted to, was from them
|
|
81
|
+
// fromMe automatically becomes false
|
|
82
|
+
false
|
|
63
83
|
// set the remoteJid to being the same as the chat the message came from
|
|
84
|
+
// TODO: investigate inconsistencies
|
|
64
85
|
msgKey.remoteJid = message.key.remoteJid
|
|
65
86
|
// set participant of the message
|
|
66
87
|
msgKey.participant = msgKey.participant || message.key.participant
|
|
@@ -68,24 +89,20 @@ const cleanMessage = (message, meId) => {
|
|
|
68
89
|
}
|
|
69
90
|
}
|
|
70
91
|
|
|
71
|
-
|
|
92
|
+
// TODO: target:audit AUDIT THIS FUNCTION AGAIN
|
|
93
|
+
const isRealMessage = (message) => {
|
|
72
94
|
const normalizedContent = normalizeMessageContent(message.message)
|
|
73
95
|
const hasSomeContent = !!getContentType(normalizedContent)
|
|
74
|
-
return (
|
|
75
|
-
!!normalizedContent ||
|
|
96
|
+
return ((!!normalizedContent ||
|
|
76
97
|
REAL_MSG_STUB_TYPES.has(message.messageStubType) ||
|
|
77
|
-
(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
hasSomeContent &&
|
|
83
|
-
!normalizedContent?.protocolMessage &&
|
|
84
|
-
!normalizedContent?.reactionMessage &&
|
|
85
|
-
!normalizedContent?.pollUpdateMessage
|
|
98
|
+
REAL_MSG_REQ_ME_STUB_TYPES.has(message.messageStubType)) &&
|
|
99
|
+
hasSomeContent &&
|
|
100
|
+
!normalizedContent?.protocolMessage &&
|
|
101
|
+
!normalizedContent?.reactionMessage &&
|
|
102
|
+
!normalizedContent?.pollUpdateMessage)
|
|
86
103
|
}
|
|
87
104
|
|
|
88
|
-
const shouldIncrementChatUnread = (message) =>
|
|
105
|
+
const shouldIncrementChatUnread = (message) => !message.key.fromMe && !message.messageStubType
|
|
89
106
|
|
|
90
107
|
/**
|
|
91
108
|
* Get the ID of the chat from the given key.
|
|
@@ -233,7 +250,7 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
|
|
|
233
250
|
const meLid = creds.me.lid
|
|
234
251
|
const { accountSettings } = creds
|
|
235
252
|
const chat = { id: jidNormalizedUser(getChatId(message.key)) }
|
|
236
|
-
const isRealMsg = isRealMessage(message
|
|
253
|
+
const isRealMsg = isRealMessage(message)
|
|
237
254
|
if (isRealMsg) {
|
|
238
255
|
chat.messages = [{ message }]
|
|
239
256
|
chat.conversationTimestamp = toNumber(message.messageTimestamp)
|
|
@@ -257,13 +274,16 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
|
|
|
257
274
|
const histNotification = protocolMsg.historySyncNotification
|
|
258
275
|
const process = shouldProcessHistoryMsg
|
|
259
276
|
const isLatest = !creds.processedHistoryMessages?.length
|
|
277
|
+
|
|
260
278
|
logger?.info({
|
|
261
279
|
histNotification,
|
|
262
280
|
process,
|
|
263
281
|
id: message.key.id,
|
|
264
|
-
isLatest
|
|
282
|
+
isLatest
|
|
265
283
|
}, 'got history notification')
|
|
284
|
+
|
|
266
285
|
if (process) {
|
|
286
|
+
// TODO: investigate
|
|
267
287
|
if (histNotification.syncType !== proto.HistorySync.HistorySyncType.ON_DEMAND) {
|
|
268
288
|
ev.emit('creds.update', {
|
|
269
289
|
processedHistoryMessages: [
|
|
@@ -272,32 +292,39 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
|
|
|
272
292
|
]
|
|
273
293
|
})
|
|
274
294
|
}
|
|
295
|
+
|
|
275
296
|
const data = await downloadAndProcessHistorySyncNotification(histNotification, options)
|
|
276
297
|
ev.emit('messaging-history.set', {
|
|
277
298
|
...data,
|
|
278
|
-
isLatest: histNotification.syncType !== proto.HistorySync.HistorySyncType.ON_DEMAND
|
|
279
|
-
? isLatest
|
|
280
|
-
: undefined,
|
|
299
|
+
isLatest: histNotification.syncType !== proto.HistorySync.HistorySyncType.ON_DEMAND ? isLatest : undefined,
|
|
281
300
|
peerDataRequestSessionId: histNotification.peerDataRequestSessionId
|
|
282
301
|
})
|
|
283
302
|
}
|
|
284
303
|
break
|
|
285
304
|
case proto.Message.ProtocolMessage.Type.APP_STATE_SYNC_KEY_SHARE:
|
|
286
305
|
const keys = protocolMsg.appStateSyncKeyShare.keys
|
|
306
|
+
|
|
287
307
|
if (keys?.length) {
|
|
288
308
|
let newAppStateSyncKeyId = ''
|
|
309
|
+
|
|
289
310
|
await keyStore.transaction(async () => {
|
|
290
311
|
const newKeys = []
|
|
312
|
+
|
|
291
313
|
for (const { keyData, keyId } of keys) {
|
|
292
314
|
const strKeyId = Buffer.from(keyId.keyId).toString('base64')
|
|
315
|
+
|
|
293
316
|
newKeys.push(strKeyId)
|
|
317
|
+
|
|
294
318
|
await keyStore.set({ 'app-state-sync-key': { [strKeyId]: keyData } })
|
|
319
|
+
|
|
295
320
|
newAppStateSyncKeyId = strKeyId
|
|
296
321
|
}
|
|
322
|
+
|
|
297
323
|
logger?.info({ newAppStateSyncKeyId, newKeys }, 'injecting new app state sync keys')
|
|
298
324
|
}, meId)
|
|
299
325
|
ev.emit('creds.update', { myAppStateKeyId: newAppStateSyncKeyId })
|
|
300
326
|
}
|
|
327
|
+
|
|
301
328
|
else {
|
|
302
329
|
logger?.info({ protocolMsg }, 'recv app state sync with 0 keys')
|
|
303
330
|
}
|
|
@@ -321,16 +348,21 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
|
|
|
321
348
|
break
|
|
322
349
|
case proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_RESPONSE_MESSAGE:
|
|
323
350
|
const response = protocolMsg.peerDataOperationRequestResponseMessage
|
|
351
|
+
|
|
324
352
|
if (response) {
|
|
325
|
-
await
|
|
353
|
+
await placeholderResendCache?.del(response.stanzaId)
|
|
354
|
+
|
|
326
355
|
// TODO: IMPLEMENT HISTORY SYNC ETC (sticker uploads etc.).
|
|
327
356
|
const { peerDataOperationResult } = response
|
|
357
|
+
|
|
328
358
|
for (const result of peerDataOperationResult) {
|
|
329
359
|
const { placeholderMessageResendResponse: retryResponse } = result
|
|
360
|
+
|
|
330
361
|
//eslint-disable-next-line max-depth
|
|
331
362
|
if (retryResponse) {
|
|
332
363
|
const webMessageInfo = proto.WebMessageInfo.decode(retryResponse.webMessageInfoBytes)
|
|
333
364
|
// wait till another upsert event is available, don't want it to be part of the PDO response message
|
|
365
|
+
// TODO: parse through proper message handling utilities (to add relevant key fields)
|
|
334
366
|
setTimeout(() => {
|
|
335
367
|
ev.emit('messages.upsert', {
|
|
336
368
|
messages: [webMessageInfo],
|
|
@@ -360,8 +392,22 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
|
|
|
360
392
|
}
|
|
361
393
|
])
|
|
362
394
|
break
|
|
395
|
+
case proto.Message.ProtocolMessage.Type.GROUP_MEMBER_LABEL_CHANGE:
|
|
396
|
+
const labelAssociationMsg = protocolMsg.memberLabel
|
|
397
|
+
|
|
398
|
+
if (labelAssociationMsg?.label) {
|
|
399
|
+
ev.emit('group.member-tag.update', {
|
|
400
|
+
groupId: chat.id,
|
|
401
|
+
label: labelAssociationMsg.label,
|
|
402
|
+
participant: message.key.participant,
|
|
403
|
+
participantAlt: message.key.participantAlt,
|
|
404
|
+
messageTimestamp: Number(message.messageTimestamp)
|
|
405
|
+
})
|
|
406
|
+
}
|
|
407
|
+
break
|
|
363
408
|
case proto.Message.ProtocolMessage.Type.LID_MIGRATION_MAPPING_SYNC:
|
|
364
409
|
const encodedPayload = protocolMsg.lidMigrationMappingSyncMessage?.encodedMappingPayload
|
|
410
|
+
|
|
365
411
|
const { pnToLidMappings, chatDbMigrationTimestamp } = proto.LIDMigrationMappingSyncPayload.decode(encodedPayload)
|
|
366
412
|
|
|
367
413
|
logger?.debug({ pnToLidMappings, chatDbMigrationTimestamp }, 'got lid mappings and chat db migration timestamp')
|
|
@@ -374,6 +420,12 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
|
|
|
374
420
|
}
|
|
375
421
|
|
|
376
422
|
await signalRepository.lidMapping.storeLIDPNMappings(pairs)
|
|
423
|
+
|
|
424
|
+
if (pairs.length) {
|
|
425
|
+
for (const { pn, lid } of pairs) {
|
|
426
|
+
await signalRepository.migrateSession(pn, lid)
|
|
427
|
+
}
|
|
428
|
+
}
|
|
377
429
|
break
|
|
378
430
|
case proto.Message.ProtocolMessage.Type.LIMIT_SHARING:
|
|
379
431
|
ev.emit('limit-sharing.update', {
|
|
@@ -398,32 +450,46 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
|
|
|
398
450
|
}
|
|
399
451
|
else if (message.messageStubType) {
|
|
400
452
|
const jid = message.key?.remoteJid
|
|
401
|
-
|
|
453
|
+
|
|
402
454
|
let participants
|
|
403
|
-
|
|
455
|
+
|
|
456
|
+
const emitParticipantsUpdate = (action) => ev.emit('group-participants.update', {
|
|
457
|
+
id: jid,
|
|
458
|
+
author: message.key.participant,
|
|
459
|
+
authorPn: message.key.participantAlt,
|
|
460
|
+
participants,
|
|
461
|
+
action
|
|
462
|
+
})
|
|
463
|
+
|
|
404
464
|
const emitGroupUpdate = (update) => {
|
|
405
|
-
ev.emit('groups.update', [
|
|
465
|
+
ev.emit('groups.update', [
|
|
466
|
+
{ id: jid, ...update, author: message.key.participant ?? undefined, authorPn: message.key.participantAlt }
|
|
467
|
+
])
|
|
406
468
|
}
|
|
469
|
+
|
|
407
470
|
const emitGroupRequestJoin = (participant, action, method) => {
|
|
408
|
-
ev.emit('group.join-request', {
|
|
471
|
+
ev.emit('group.join-request', {
|
|
472
|
+
id: jid,
|
|
473
|
+
author: message.key.participant,
|
|
474
|
+
authorPn: message.key.participantAlt,
|
|
475
|
+
participant: participant.lid,
|
|
476
|
+
participantPn: participant.pn,
|
|
477
|
+
action,
|
|
478
|
+
method: method
|
|
479
|
+
})
|
|
409
480
|
}
|
|
410
|
-
|
|
481
|
+
|
|
482
|
+
const participantsIncludesMe = () => participants.find(jid => areJidsSameUser(meId, jid.phoneNumber)) // ADD SUPPORT FOR LID
|
|
411
483
|
switch (message.messageStubType) {
|
|
412
484
|
case WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER:
|
|
413
|
-
participants = message.messageStubParameters || []
|
|
485
|
+
participants = message.messageStubParameters.map((a) => JSON.parse(a)) || []
|
|
414
486
|
emitParticipantsUpdate('modify')
|
|
415
487
|
break
|
|
416
488
|
case WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
|
|
417
|
-
participants = message.messageStubParameters || [];
|
|
418
|
-
emitParticipantsUpdate('leave');
|
|
419
|
-
// mark the chat read only if you left the group
|
|
420
|
-
if (participantsIncludesMe()) {
|
|
421
|
-
chat.readOnly = true;
|
|
422
|
-
}
|
|
423
|
-
break;
|
|
424
489
|
case WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
|
|
425
|
-
participants = message.messageStubParameters || []
|
|
490
|
+
participants = message.messageStubParameters.map((a) => JSON.parse(a)) || []
|
|
426
491
|
emitParticipantsUpdate('remove')
|
|
492
|
+
|
|
427
493
|
// mark the chat read only if you left the group
|
|
428
494
|
if (participantsIncludesMe()) {
|
|
429
495
|
chat.readOnly = true
|
|
@@ -431,27 +497,21 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
|
|
|
431
497
|
break
|
|
432
498
|
case WAMessageStubType.GROUP_PARTICIPANT_ADD:
|
|
433
499
|
case WAMessageStubType.GROUP_PARTICIPANT_INVITE:
|
|
434
|
-
let actionGp = 'invite'
|
|
435
|
-
participants = message.messageStubParameters || []
|
|
436
|
-
if (participantsIncludesMe()) chat.readOnly = false;
|
|
437
|
-
if (message?.key?.participant && !participants.includes(message?.key?.participant)) {
|
|
438
|
-
actionGp = 'approval-invite'
|
|
439
|
-
}
|
|
440
500
|
case WAMessageStubType.GROUP_PARTICIPANT_ADD_REQUEST_JOIN:
|
|
441
|
-
participants = message.messageStubParameters || []
|
|
501
|
+
participants = message.messageStubParameters.map((a) => JSON.parse(a)) || []
|
|
502
|
+
|
|
442
503
|
if (participantsIncludesMe()) {
|
|
443
504
|
chat.readOnly = false
|
|
444
505
|
}
|
|
506
|
+
|
|
445
507
|
emitParticipantsUpdate('add')
|
|
446
508
|
break
|
|
447
509
|
case WAMessageStubType.GROUP_PARTICIPANT_DEMOTE:
|
|
448
|
-
|
|
449
|
-
participants = message.messageStubParameters || []
|
|
510
|
+
participants = message.messageStubParameters.map((a) => JSON.parse(a)) || []
|
|
450
511
|
emitParticipantsUpdate('demote')
|
|
451
512
|
break
|
|
452
513
|
case WAMessageStubType.GROUP_PARTICIPANT_PROMOTE:
|
|
453
|
-
|
|
454
|
-
participants = message.messageStubParameters || []
|
|
514
|
+
participants = message.messageStubParameters.map((a) => JSON.parse(a)) || []
|
|
455
515
|
emitParticipantsUpdate('promote')
|
|
456
516
|
break
|
|
457
517
|
case WAMessageStubType.GROUP_CHANGE_ANNOUNCE:
|
|
@@ -484,8 +544,8 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
|
|
|
484
544
|
const approvalMode = message.messageStubParameters?.[0]
|
|
485
545
|
emitGroupUpdate({ joinApprovalMode: approvalMode === 'on' })
|
|
486
546
|
break
|
|
487
|
-
case WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD:
|
|
488
|
-
const participant = message.messageStubParameters?.[0]
|
|
547
|
+
case WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD: // TODO: Add other events
|
|
548
|
+
const participant = JSON.parse(message.messageStubParameters?.[0])
|
|
489
549
|
const action = message.messageStubParameters?.[1]
|
|
490
550
|
const method = message.messageStubParameters?.[2]
|
|
491
551
|
emitGroupRequestJoin(participant, action, method)
|
|
@@ -650,7 +710,7 @@ const processMessage = async (message, { shouldProcessHistoryMsg, placeholderRes
|
|
|
650
710
|
const encComment = content.encCommentMessage
|
|
651
711
|
const creationMsgKey = encComment.targetMessageKey
|
|
652
712
|
|
|
653
|
-
// we need to fetch the message to get the
|
|
713
|
+
// we need to fetch the message to get the comment enc key
|
|
654
714
|
const commentMsg = await getMessage(creationMsgKey)
|
|
655
715
|
if (commentMsg) {
|
|
656
716
|
try {
|