violetics 7.0.1-alpha → 7.0.2-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +3 -2
- package/README.md +1001 -232
- package/WAProto/index.js +75379 -142631
- package/engine-requirements.js +11 -8
- package/lib/Defaults/index.js +132 -146
- package/lib/Signal/Group/ciphertext-message.js +2 -6
- package/lib/Signal/Group/group-session-builder.js +7 -42
- package/lib/Signal/Group/group_cipher.js +37 -52
- package/lib/Signal/Group/index.js +11 -57
- package/lib/Signal/Group/keyhelper.js +7 -45
- package/lib/Signal/Group/sender-chain-key.js +7 -16
- package/lib/Signal/Group/sender-key-distribution-message.js +8 -12
- package/lib/Signal/Group/sender-key-message.js +9 -13
- package/lib/Signal/Group/sender-key-name.js +2 -6
- package/lib/Signal/Group/sender-key-record.js +9 -22
- package/lib/Signal/Group/sender-key-state.js +27 -43
- package/lib/Signal/Group/sender-message-key.js +4 -8
- package/lib/Signal/libsignal.js +319 -94
- package/lib/Signal/lid-mapping.js +224 -139
- package/lib/Socket/Client/index.js +2 -19
- package/lib/Socket/Client/types.js +10 -0
- package/lib/Socket/Client/websocket.js +53 -0
- package/lib/Socket/business.js +162 -44
- package/lib/Socket/chats.js +477 -418
- package/lib/Socket/communities.js +430 -0
- package/lib/Socket/groups.js +110 -99
- package/lib/Socket/index.js +10 -10
- package/lib/Socket/messages-recv.js +884 -561
- package/lib/Socket/messages-send.js +859 -428
- package/lib/Socket/mex.js +41 -0
- package/lib/Socket/newsletter.js +195 -390
- package/lib/Socket/socket.js +465 -315
- package/lib/Store/index.js +3 -10
- package/lib/Store/make-in-memory-store.js +73 -79
- package/lib/Store/make-ordered-dictionary.js +4 -7
- package/lib/Store/object-repository.js +2 -6
- package/lib/Types/Auth.js +1 -2
- package/lib/Types/Bussines.js +1 -0
- package/lib/Types/Call.js +1 -2
- package/lib/Types/Chat.js +7 -4
- package/lib/Types/Contact.js +1 -2
- package/lib/Types/Events.js +1 -2
- package/lib/Types/GroupMetadata.js +1 -2
- package/lib/Types/Label.js +2 -5
- package/lib/Types/LabelAssociation.js +2 -5
- package/lib/Types/Message.js +17 -9
- package/lib/Types/Newsletter.js +33 -38
- package/lib/Types/Product.js +1 -2
- package/lib/Types/Signal.js +1 -2
- package/lib/Types/Socket.js +2 -2
- package/lib/Types/State.js +12 -2
- package/lib/Types/USync.js +1 -2
- package/lib/Types/index.js +14 -31
- package/lib/Utils/auth-utils.js +228 -152
- package/lib/Utils/browser-utils.js +28 -0
- package/lib/Utils/business.js +66 -70
- package/lib/Utils/chat-utils.js +331 -249
- package/lib/Utils/crypto.js +57 -91
- package/lib/Utils/decode-wa-message.js +168 -84
- package/lib/Utils/event-buffer.js +138 -80
- package/lib/Utils/generics.js +180 -297
- package/lib/Utils/history.js +83 -49
- package/lib/Utils/identity-change-handler.js +48 -0
- package/lib/Utils/index.js +19 -33
- package/lib/Utils/link-preview.js +14 -23
- package/lib/Utils/logger.js +2 -7
- package/lib/Utils/lt-hash.js +2 -46
- package/lib/Utils/make-mutex.js +24 -47
- package/lib/Utils/message-retry-manager.js +224 -0
- package/lib/Utils/messages-media.js +501 -496
- package/lib/Utils/messages.js +1428 -362
- package/lib/Utils/noise-handler.js +145 -100
- package/lib/Utils/pre-key-manager.js +105 -0
- package/lib/Utils/process-message.js +356 -150
- package/lib/Utils/reporting-utils.js +257 -0
- package/lib/Utils/signal.js +78 -73
- package/lib/Utils/sync-action-utils.js +47 -0
- package/lib/Utils/tc-token-utils.js +17 -0
- package/lib/Utils/use-multi-file-auth-state.js +35 -45
- package/lib/Utils/validate-connection.js +91 -107
- package/lib/WABinary/constants.js +1300 -1304
- package/lib/WABinary/decode.js +26 -48
- package/lib/WABinary/encode.js +109 -155
- package/lib/WABinary/generic-utils.js +161 -149
- package/lib/WABinary/index.js +5 -21
- package/lib/WABinary/jid-utils.js +73 -40
- package/lib/WABinary/types.js +1 -2
- package/lib/WAM/BinaryInfo.js +2 -6
- package/lib/WAM/constants.js +19070 -11568
- package/lib/WAM/encode.js +17 -23
- package/lib/WAM/index.js +3 -19
- package/lib/WAUSync/Protocols/USyncContactProtocol.js +8 -12
- package/lib/WAUSync/Protocols/USyncDeviceProtocol.js +11 -15
- package/lib/WAUSync/Protocols/USyncDisappearingModeProtocol.js +9 -13
- package/lib/WAUSync/Protocols/USyncStatusProtocol.js +9 -14
- package/lib/WAUSync/Protocols/UsyncBotProfileProtocol.js +20 -23
- package/lib/WAUSync/Protocols/UsyncLIDProtocol.js +13 -9
- package/lib/WAUSync/Protocols/index.js +4 -20
- package/lib/WAUSync/USyncQuery.js +40 -36
- package/lib/WAUSync/USyncUser.js +2 -6
- package/lib/WAUSync/index.js +3 -19
- package/lib/index.js +11 -44
- package/package.json +74 -107
- package/lib/Defaults/baileys-version.json +0 -3
- package/lib/Defaults/phonenumber-mcc.json +0 -223
- package/lib/Signal/Group/queue-job.js +0 -57
- package/lib/Socket/Client/abstract-socket-client.js +0 -13
- package/lib/Socket/Client/mobile-socket-client.js +0 -65
- package/lib/Socket/Client/web-socket-client.js +0 -118
- package/lib/Socket/groupStatus.js +0 -637
- package/lib/Socket/registration.js +0 -166
- package/lib/Socket/usync.js +0 -70
- package/lib/Store/make-cache-manager-store.js +0 -83
- package/lib/Utils/baileys-event-stream.js +0 -63
|
@@ -1,33 +1,38 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const crypto_1 = require("./crypto");
|
|
9
|
-
const generics_1 = require("./generics");
|
|
10
|
-
const history_1 = require("./history");
|
|
1
|
+
import { proto } from '../../WAProto/index.js';
|
|
2
|
+
import { WAMessageStubType } from '../Types/index.js';
|
|
3
|
+
import { getContentType, normalizeMessageContent } from '../Utils/messages.js';
|
|
4
|
+
import { areJidsSameUser, isHostedLidUser, isHostedPnUser, isJidBroadcast, isJidStatusBroadcast, isLidUser, jidDecode, jidEncode, jidNormalizedUser } from '../WABinary/index.js';
|
|
5
|
+
import { aesDecryptGCM, hmacSign } from './crypto.js';
|
|
6
|
+
import { getKeyAuthor, toNumber } from './generics.js';
|
|
7
|
+
import { downloadAndProcessHistorySyncNotification } from './history.js';
|
|
11
8
|
const REAL_MSG_STUB_TYPES = new Set([
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
]);
|
|
17
|
-
const REAL_MSG_REQ_ME_STUB_TYPES = new Set([
|
|
18
|
-
Types_1.WAMessageStubType.GROUP_PARTICIPANT_ADD
|
|
9
|
+
WAMessageStubType.CALL_MISSED_GROUP_VIDEO,
|
|
10
|
+
WAMessageStubType.CALL_MISSED_GROUP_VOICE,
|
|
11
|
+
WAMessageStubType.CALL_MISSED_VIDEO,
|
|
12
|
+
WAMessageStubType.CALL_MISSED_VOICE
|
|
19
13
|
]);
|
|
14
|
+
const REAL_MSG_REQ_ME_STUB_TYPES = new Set([WAMessageStubType.GROUP_PARTICIPANT_ADD]);
|
|
20
15
|
/** Cleans a received message to further processing */
|
|
21
|
-
const cleanMessage = (message, meId) => {
|
|
16
|
+
export const cleanMessage = (message, meId, meLid) => {
|
|
22
17
|
// ensure remoteJid and participant doesn't have device or agent in it
|
|
23
|
-
message.key.remoteJid
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
if (isHostedPnUser(message.key.remoteJid) || isHostedLidUser(message.key.remoteJid)) {
|
|
19
|
+
message.key.remoteJid = jidEncode(jidDecode(message.key?.remoteJid)?.user, isHostedPnUser(message.key.remoteJid) ? 's.whatsapp.net' : 'lid');
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
message.key.remoteJid = jidNormalizedUser(message.key.remoteJid);
|
|
23
|
+
}
|
|
24
|
+
if (isHostedPnUser(message.key.participant) || isHostedLidUser(message.key.participant)) {
|
|
25
|
+
message.key.participant = jidEncode(jidDecode(message.key.participant)?.user, isHostedPnUser(message.key.participant) ? 's.whatsapp.net' : 'lid');
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
message.key.participant = jidNormalizedUser(message.key.participant);
|
|
29
|
+
}
|
|
30
|
+
const content = normalizeMessageContent(message.message);
|
|
26
31
|
// if the message has a reaction, ensure fromMe & remoteJid are from our perspective
|
|
27
|
-
if (content
|
|
32
|
+
if (content?.reactionMessage) {
|
|
28
33
|
normaliseKey(content.reactionMessage.key);
|
|
29
34
|
}
|
|
30
|
-
if (content
|
|
35
|
+
if (content?.pollUpdateMessage) {
|
|
31
36
|
normaliseKey(content.pollUpdateMessage.pollCreationMessageKey);
|
|
32
37
|
}
|
|
33
38
|
function normaliseKey(msgKey) {
|
|
@@ -37,54 +42,49 @@ const cleanMessage = (message, meId) => {
|
|
|
37
42
|
// if the sender believed the message being reacted to is not from them
|
|
38
43
|
// we've to correct the key to be from them, or some other participant
|
|
39
44
|
msgKey.fromMe = !msgKey.fromMe
|
|
40
|
-
?
|
|
41
|
-
|
|
42
|
-
//
|
|
43
|
-
|
|
45
|
+
? areJidsSameUser(msgKey.participant || msgKey.remoteJid, meId) ||
|
|
46
|
+
areJidsSameUser(msgKey.participant || msgKey.remoteJid, meLid)
|
|
47
|
+
: // if the message being reacted to, was from them
|
|
48
|
+
// fromMe automatically becomes false
|
|
49
|
+
false;
|
|
44
50
|
// set the remoteJid to being the same as the chat the message came from
|
|
51
|
+
// TODO: investigate inconsistencies
|
|
45
52
|
msgKey.remoteJid = message.key.remoteJid;
|
|
46
53
|
// set participant of the message
|
|
47
54
|
msgKey.participant = msgKey.participant || message.key.participant;
|
|
48
55
|
}
|
|
49
56
|
}
|
|
50
57
|
};
|
|
51
|
-
|
|
52
|
-
const isRealMessage = (message
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
&&
|
|
61
|
-
|
|
62
|
-
&& !(normalizedContent === null || normalizedContent === void 0 ? void 0 : normalizedContent.reactionMessage)
|
|
63
|
-
&& !(normalizedContent === null || normalizedContent === void 0 ? void 0 : normalizedContent.pollUpdateMessage);
|
|
58
|
+
// TODO: target:audit AUDIT THIS FUNCTION AGAIN
|
|
59
|
+
export const isRealMessage = (message) => {
|
|
60
|
+
const normalizedContent = normalizeMessageContent(message.message);
|
|
61
|
+
const hasSomeContent = !!getContentType(normalizedContent);
|
|
62
|
+
return ((!!normalizedContent ||
|
|
63
|
+
REAL_MSG_STUB_TYPES.has(message.messageStubType) ||
|
|
64
|
+
REAL_MSG_REQ_ME_STUB_TYPES.has(message.messageStubType)) &&
|
|
65
|
+
hasSomeContent &&
|
|
66
|
+
!normalizedContent?.protocolMessage &&
|
|
67
|
+
!normalizedContent?.reactionMessage &&
|
|
68
|
+
!normalizedContent?.pollUpdateMessage);
|
|
64
69
|
};
|
|
65
|
-
|
|
66
|
-
const shouldIncrementChatUnread = (message) => (!message.key.fromMe && !message.messageStubType);
|
|
67
|
-
exports.shouldIncrementChatUnread = shouldIncrementChatUnread;
|
|
70
|
+
export const shouldIncrementChatUnread = (message) => !message.key.fromMe && !message.messageStubType;
|
|
68
71
|
/**
|
|
69
72
|
* Get the ID of the chat from the given key.
|
|
70
73
|
* Typically -- that'll be the remoteJid, but for broadcasts, it'll be the participant
|
|
71
74
|
*/
|
|
72
|
-
const getChatId = ({ remoteJid, participant, fromMe }) => {
|
|
73
|
-
if ((
|
|
74
|
-
&& !(0, WABinary_1.isJidStatusBroadcast)(remoteJid)
|
|
75
|
-
&& !fromMe) {
|
|
75
|
+
export const getChatId = ({ remoteJid, participant, fromMe }) => {
|
|
76
|
+
if (isJidBroadcast(remoteJid) && !isJidStatusBroadcast(remoteJid) && !fromMe) {
|
|
76
77
|
return participant;
|
|
77
78
|
}
|
|
78
79
|
return remoteJid;
|
|
79
80
|
};
|
|
80
|
-
exports.getChatId = getChatId;
|
|
81
81
|
/**
|
|
82
82
|
* Decrypt a poll vote
|
|
83
83
|
* @param vote encrypted vote
|
|
84
84
|
* @param ctx additional info about the poll required for decryption
|
|
85
85
|
* @returns list of SHA256 options
|
|
86
86
|
*/
|
|
87
|
-
function decryptPollVote({ encPayload, encIv }, { pollCreatorJid, pollMsgId, pollEncKey, voterJid
|
|
87
|
+
export function decryptPollVote({ encPayload, encIv }, { pollCreatorJid, pollMsgId, pollEncKey, voterJid }) {
|
|
88
88
|
const sign = Buffer.concat([
|
|
89
89
|
toBinary(pollMsgId),
|
|
90
90
|
toBinary(pollCreatorJid),
|
|
@@ -92,64 +92,98 @@ function decryptPollVote({ encPayload, encIv }, { pollCreatorJid, pollMsgId, pol
|
|
|
92
92
|
toBinary('Poll Vote'),
|
|
93
93
|
new Uint8Array([1])
|
|
94
94
|
]);
|
|
95
|
-
const key0 =
|
|
96
|
-
const decKey =
|
|
95
|
+
const key0 = hmacSign(pollEncKey, new Uint8Array(32), 'sha256');
|
|
96
|
+
const decKey = hmacSign(sign, key0, 'sha256');
|
|
97
97
|
const aad = toBinary(`${pollMsgId}\u0000${voterJid}`);
|
|
98
|
-
const decrypted =
|
|
99
|
-
return
|
|
98
|
+
const decrypted = aesDecryptGCM(encPayload, decKey, encIv, aad);
|
|
99
|
+
return proto.Message.PollVoteMessage.decode(decrypted);
|
|
100
|
+
function toBinary(txt) {
|
|
101
|
+
return Buffer.from(txt);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Decrypt an event response
|
|
106
|
+
* @param response encrypted event response
|
|
107
|
+
* @param ctx additional info about the event required for decryption
|
|
108
|
+
* @returns event response message
|
|
109
|
+
*/
|
|
110
|
+
export function decryptEventResponse({ encPayload, encIv }, { eventCreatorJid, eventMsgId, eventEncKey, responderJid }) {
|
|
111
|
+
const sign = Buffer.concat([
|
|
112
|
+
toBinary(eventMsgId),
|
|
113
|
+
toBinary(eventCreatorJid),
|
|
114
|
+
toBinary(responderJid),
|
|
115
|
+
toBinary('Event Response'),
|
|
116
|
+
new Uint8Array([1])
|
|
117
|
+
]);
|
|
118
|
+
const key0 = hmacSign(eventEncKey, new Uint8Array(32), 'sha256');
|
|
119
|
+
const decKey = hmacSign(sign, key0, 'sha256');
|
|
120
|
+
const aad = toBinary(`${eventMsgId}\u0000${responderJid}`);
|
|
121
|
+
const decrypted = aesDecryptGCM(encPayload, decKey, encIv, aad);
|
|
122
|
+
return proto.Message.EventResponseMessage.decode(decrypted);
|
|
100
123
|
function toBinary(txt) {
|
|
101
124
|
return Buffer.from(txt);
|
|
102
125
|
}
|
|
103
126
|
}
|
|
104
|
-
|
|
105
|
-
const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, keyStore, logger, options, getMessage }) => {
|
|
106
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
127
|
+
const processMessage = async (message, { shouldProcessHistoryMsg, placeholderResendCache, ev, creds, signalRepository, keyStore, logger, options, getMessage }) => {
|
|
107
128
|
const meId = creds.me.id;
|
|
108
129
|
const { accountSettings } = creds;
|
|
109
|
-
const chat = { id:
|
|
110
|
-
const isRealMsg =
|
|
130
|
+
const chat = { id: jidNormalizedUser(getChatId(message.key)) };
|
|
131
|
+
const isRealMsg = isRealMessage(message);
|
|
111
132
|
if (isRealMsg) {
|
|
112
|
-
chat.
|
|
133
|
+
chat.messages = [{ message }];
|
|
134
|
+
chat.conversationTimestamp = toNumber(message.messageTimestamp);
|
|
113
135
|
// only increment unread count if not CIPHERTEXT and from another person
|
|
114
|
-
if (
|
|
136
|
+
if (shouldIncrementChatUnread(message)) {
|
|
115
137
|
chat.unreadCount = (chat.unreadCount || 0) + 1;
|
|
116
138
|
}
|
|
117
139
|
}
|
|
118
|
-
const content =
|
|
140
|
+
const content = normalizeMessageContent(message.message);
|
|
119
141
|
// unarchive chat if it's a real message, or someone reacted to our message
|
|
120
142
|
// and we've the unarchive chats setting on
|
|
121
|
-
if ((isRealMsg ||
|
|
122
|
-
&& (accountSettings === null || accountSettings === void 0 ? void 0 : accountSettings.unarchiveChats)) {
|
|
143
|
+
if ((isRealMsg || content?.reactionMessage?.key?.fromMe) && accountSettings?.unarchiveChats) {
|
|
123
144
|
chat.archived = false;
|
|
124
145
|
chat.readOnly = false;
|
|
125
146
|
}
|
|
126
|
-
const protocolMsg = content
|
|
147
|
+
const protocolMsg = content?.protocolMessage;
|
|
127
148
|
if (protocolMsg) {
|
|
128
149
|
switch (protocolMsg.type) {
|
|
129
|
-
case
|
|
150
|
+
case proto.Message.ProtocolMessage.Type.HISTORY_SYNC_NOTIFICATION:
|
|
130
151
|
const histNotification = protocolMsg.historySyncNotification;
|
|
131
152
|
const process = shouldProcessHistoryMsg;
|
|
132
|
-
const isLatest = !
|
|
133
|
-
logger
|
|
153
|
+
const isLatest = !creds.processedHistoryMessages?.length;
|
|
154
|
+
logger?.info({
|
|
134
155
|
histNotification,
|
|
135
156
|
process,
|
|
136
157
|
id: message.key.id,
|
|
137
|
-
isLatest
|
|
158
|
+
isLatest
|
|
138
159
|
}, 'got history notification');
|
|
139
160
|
if (process) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
161
|
+
// TODO: investigate
|
|
162
|
+
if (histNotification.syncType !== proto.HistorySync.HistorySyncType.ON_DEMAND) {
|
|
163
|
+
ev.emit('creds.update', {
|
|
164
|
+
processedHistoryMessages: [
|
|
165
|
+
...(creds.processedHistoryMessages || []),
|
|
166
|
+
{ key: message.key, messageTimestamp: message.messageTimestamp }
|
|
167
|
+
]
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
const data = await downloadAndProcessHistorySyncNotification(histNotification, options, logger);
|
|
171
|
+
if (data.lidPnMappings?.length) {
|
|
172
|
+
logger?.debug({ count: data.lidPnMappings.length }, 'processing LID-PN mappings from history sync');
|
|
173
|
+
await signalRepository.lidMapping
|
|
174
|
+
.storeLIDPNMappings(data.lidPnMappings)
|
|
175
|
+
.catch(err => logger?.warn({ err }, 'failed to store LID-PN mappings from history sync'));
|
|
176
|
+
}
|
|
177
|
+
ev.emit('messaging-history.set', {
|
|
178
|
+
...data,
|
|
179
|
+
isLatest: histNotification.syncType !== proto.HistorySync.HistorySyncType.ON_DEMAND ? isLatest : undefined,
|
|
180
|
+
peerDataRequestSessionId: histNotification.peerDataRequestSessionId
|
|
145
181
|
});
|
|
146
|
-
const data = await (0, history_1.downloadAndProcessHistorySyncNotification)(histNotification, options);
|
|
147
|
-
ev.emit('messaging-history.set', { ...data, isLatest });
|
|
148
182
|
}
|
|
149
183
|
break;
|
|
150
|
-
case
|
|
184
|
+
case proto.Message.ProtocolMessage.Type.APP_STATE_SYNC_KEY_SHARE:
|
|
151
185
|
const keys = protocolMsg.appStateSyncKeyShare.keys;
|
|
152
|
-
if (keys
|
|
186
|
+
if (keys?.length) {
|
|
153
187
|
let newAppStateSyncKeyId = '';
|
|
154
188
|
await keyStore.transaction(async () => {
|
|
155
189
|
const newKeys = [];
|
|
@@ -159,138 +193,306 @@ const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, key
|
|
|
159
193
|
await keyStore.set({ 'app-state-sync-key': { [strKeyId]: keyData } });
|
|
160
194
|
newAppStateSyncKeyId = strKeyId;
|
|
161
195
|
}
|
|
162
|
-
logger
|
|
163
|
-
});
|
|
196
|
+
logger?.info({ newAppStateSyncKeyId, newKeys }, 'injecting new app state sync keys');
|
|
197
|
+
}, meId);
|
|
164
198
|
ev.emit('creds.update', { myAppStateKeyId: newAppStateSyncKeyId });
|
|
165
199
|
}
|
|
166
200
|
else {
|
|
167
|
-
logger
|
|
201
|
+
logger?.info({ protocolMsg }, 'recv app state sync with 0 keys');
|
|
168
202
|
}
|
|
169
203
|
break;
|
|
170
|
-
case
|
|
204
|
+
case proto.Message.ProtocolMessage.Type.REVOKE:
|
|
171
205
|
ev.emit('messages.update', [
|
|
172
206
|
{
|
|
173
207
|
key: {
|
|
174
208
|
...message.key,
|
|
175
209
|
id: protocolMsg.key.id
|
|
176
210
|
},
|
|
177
|
-
update: { message: null, messageStubType:
|
|
211
|
+
update: { message: null, messageStubType: WAMessageStubType.REVOKE, key: message.key }
|
|
178
212
|
}
|
|
179
213
|
]);
|
|
180
214
|
break;
|
|
181
|
-
case
|
|
215
|
+
case proto.Message.ProtocolMessage.Type.EPHEMERAL_SETTING:
|
|
182
216
|
Object.assign(chat, {
|
|
183
|
-
ephemeralSettingTimestamp:
|
|
217
|
+
ephemeralSettingTimestamp: toNumber(message.messageTimestamp),
|
|
184
218
|
ephemeralExpiration: protocolMsg.ephemeralExpiration || null
|
|
185
219
|
});
|
|
186
220
|
break;
|
|
187
|
-
case
|
|
221
|
+
case proto.Message.ProtocolMessage.Type.PEER_DATA_OPERATION_REQUEST_RESPONSE_MESSAGE:
|
|
188
222
|
const response = protocolMsg.peerDataOperationRequestResponseMessage;
|
|
189
223
|
if (response) {
|
|
190
|
-
|
|
224
|
+
// TODO: IMPLEMENT HISTORY SYNC ETC (sticker uploads etc.).
|
|
225
|
+
const peerDataOperationResult = response.peerDataOperationResult || [];
|
|
191
226
|
for (const result of peerDataOperationResult) {
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
227
|
+
const retryResponse = result?.placeholderMessageResendResponse;
|
|
228
|
+
//eslint-disable-next-line max-depth
|
|
229
|
+
if (!retryResponse?.webMessageInfoBytes) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
//eslint-disable-next-line max-depth
|
|
233
|
+
try {
|
|
234
|
+
const webMessageInfo = proto.WebMessageInfo.decode(retryResponse.webMessageInfoBytes);
|
|
235
|
+
const msgId = webMessageInfo.key?.id;
|
|
236
|
+
// Retrieve cached original message data (preserves LID details,
|
|
237
|
+
// timestamps, etc. that the phone may omit in its PDO response)
|
|
238
|
+
const cachedData = msgId ? await placeholderResendCache?.get(msgId) : undefined;
|
|
239
|
+
//eslint-disable-next-line max-depth
|
|
240
|
+
if (msgId) {
|
|
241
|
+
await placeholderResendCache?.del(msgId);
|
|
242
|
+
}
|
|
243
|
+
let finalMsg;
|
|
244
|
+
//eslint-disable-next-line max-depth
|
|
245
|
+
if (cachedData && typeof cachedData === 'object') {
|
|
246
|
+
// Apply decoded message content onto cached metadata (preserves LID etc.)
|
|
247
|
+
cachedData.message = webMessageInfo.message;
|
|
248
|
+
//eslint-disable-next-line max-depth
|
|
249
|
+
if (webMessageInfo.messageTimestamp) {
|
|
250
|
+
cachedData.messageTimestamp = webMessageInfo.messageTimestamp;
|
|
251
|
+
}
|
|
252
|
+
finalMsg = cachedData;
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
finalMsg = webMessageInfo;
|
|
256
|
+
}
|
|
257
|
+
logger?.debug({ msgId, requestId: response.stanzaId }, 'received placeholder resend');
|
|
258
|
+
ev.emit('messages.upsert', {
|
|
259
|
+
messages: [finalMsg],
|
|
260
|
+
type: 'notify',
|
|
261
|
+
requestId: response.stanzaId
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
catch (err) {
|
|
265
|
+
logger?.warn({ err, stanzaId: response.stanzaId }, 'failed to decode placeholder resend response');
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
break;
|
|
270
|
+
case proto.Message.ProtocolMessage.Type.MESSAGE_EDIT:
|
|
271
|
+
ev.emit('messages.update', [
|
|
272
|
+
{
|
|
273
|
+
// flip the sender / fromMe properties because they're in the perspective of the sender
|
|
274
|
+
key: { ...message.key, id: protocolMsg.key?.id },
|
|
275
|
+
update: {
|
|
276
|
+
message: {
|
|
277
|
+
editedMessage: {
|
|
278
|
+
message: protocolMsg.editedMessage
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
messageTimestamp: protocolMsg.timestampMs
|
|
282
|
+
? Math.floor(toNumber(protocolMsg.timestampMs) / 1000)
|
|
283
|
+
: message.messageTimestamp
|
|
198
284
|
}
|
|
199
285
|
}
|
|
286
|
+
]);
|
|
287
|
+
break;
|
|
288
|
+
case proto.Message.ProtocolMessage.Type.GROUP_MEMBER_LABEL_CHANGE:
|
|
289
|
+
const labelAssociationMsg = protocolMsg.memberLabel;
|
|
290
|
+
if (labelAssociationMsg?.label) {
|
|
291
|
+
ev.emit('group.member-tag.update', {
|
|
292
|
+
groupId: chat.id,
|
|
293
|
+
label: labelAssociationMsg.label,
|
|
294
|
+
participant: message.key.participant,
|
|
295
|
+
participantAlt: message.key.participantAlt,
|
|
296
|
+
messageTimestamp: Number(message.messageTimestamp)
|
|
297
|
+
});
|
|
200
298
|
}
|
|
201
299
|
break;
|
|
300
|
+
case proto.Message.ProtocolMessage.Type.LID_MIGRATION_MAPPING_SYNC:
|
|
301
|
+
const encodedPayload = protocolMsg.lidMigrationMappingSyncMessage?.encodedMappingPayload;
|
|
302
|
+
const { pnToLidMappings, chatDbMigrationTimestamp } = proto.LIDMigrationMappingSyncPayload.decode(encodedPayload);
|
|
303
|
+
logger?.debug({ pnToLidMappings, chatDbMigrationTimestamp }, 'got lid mappings and chat db migration timestamp');
|
|
304
|
+
const pairs = [];
|
|
305
|
+
for (const { pn, latestLid, assignedLid } of pnToLidMappings) {
|
|
306
|
+
const lid = latestLid || assignedLid;
|
|
307
|
+
pairs.push({ lid: `${lid}@lid`, pn: `${pn}@s.whatsapp.net` });
|
|
308
|
+
}
|
|
309
|
+
await signalRepository.lidMapping.storeLIDPNMappings(pairs);
|
|
310
|
+
if (pairs.length) {
|
|
311
|
+
for (const { pn, lid } of pairs) {
|
|
312
|
+
await signalRepository.migrateSession(pn, lid);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
202
315
|
}
|
|
203
316
|
}
|
|
204
|
-
else if (content
|
|
317
|
+
else if (content?.reactionMessage) {
|
|
205
318
|
const reaction = {
|
|
206
319
|
...content.reactionMessage,
|
|
207
|
-
key: message.key
|
|
320
|
+
key: message.key
|
|
208
321
|
};
|
|
209
|
-
ev.emit('messages.reaction', [
|
|
322
|
+
ev.emit('messages.reaction', [
|
|
323
|
+
{
|
|
210
324
|
reaction,
|
|
211
|
-
key: content.reactionMessage
|
|
212
|
-
}
|
|
325
|
+
key: content.reactionMessage?.key
|
|
326
|
+
}
|
|
327
|
+
]);
|
|
328
|
+
}
|
|
329
|
+
else if (content?.encEventResponseMessage) {
|
|
330
|
+
const encEventResponse = content.encEventResponseMessage;
|
|
331
|
+
const creationMsgKey = encEventResponse.eventCreationMessageKey;
|
|
332
|
+
// we need to fetch the event creation message to get the event enc key
|
|
333
|
+
const eventMsg = await getMessage(creationMsgKey);
|
|
334
|
+
if (eventMsg) {
|
|
335
|
+
try {
|
|
336
|
+
const meIdNormalised = jidNormalizedUser(meId);
|
|
337
|
+
// all jids need to be PN
|
|
338
|
+
const eventCreatorKey = creationMsgKey.participant || creationMsgKey.remoteJid;
|
|
339
|
+
const eventCreatorPn = isLidUser(eventCreatorKey)
|
|
340
|
+
? await signalRepository.lidMapping.getPNForLID(eventCreatorKey)
|
|
341
|
+
: eventCreatorKey;
|
|
342
|
+
const eventCreatorJid = getKeyAuthor({ remoteJid: jidNormalizedUser(eventCreatorPn), fromMe: meIdNormalised === eventCreatorPn }, meIdNormalised);
|
|
343
|
+
const responderJid = getKeyAuthor(message.key, meIdNormalised);
|
|
344
|
+
const eventEncKey = eventMsg?.messageContextInfo?.messageSecret;
|
|
345
|
+
if (!eventEncKey) {
|
|
346
|
+
logger?.warn({ creationMsgKey }, 'event response: missing messageSecret for decryption');
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
const responseMsg = decryptEventResponse(encEventResponse, {
|
|
350
|
+
eventEncKey,
|
|
351
|
+
eventCreatorJid,
|
|
352
|
+
eventMsgId: creationMsgKey.id,
|
|
353
|
+
responderJid
|
|
354
|
+
});
|
|
355
|
+
const eventResponse = {
|
|
356
|
+
eventResponseMessageKey: message.key,
|
|
357
|
+
senderTimestampMs: responseMsg.timestampMs,
|
|
358
|
+
response: responseMsg
|
|
359
|
+
};
|
|
360
|
+
ev.emit('messages.update', [
|
|
361
|
+
{
|
|
362
|
+
key: creationMsgKey,
|
|
363
|
+
update: {
|
|
364
|
+
eventResponses: [eventResponse]
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
]);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
catch (err) {
|
|
371
|
+
logger?.warn({ err, creationMsgKey }, 'failed to decrypt event response');
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
logger?.warn({ creationMsgKey }, 'event creation message not found, cannot decrypt response');
|
|
376
|
+
}
|
|
213
377
|
}
|
|
214
378
|
else if (message.messageStubType) {
|
|
215
|
-
const jid = message.key
|
|
379
|
+
const jid = message.key?.remoteJid;
|
|
216
380
|
//let actor = whatsappID (message.participant)
|
|
217
381
|
let participants;
|
|
218
|
-
const emitParticipantsUpdate = (action) =>
|
|
382
|
+
const emitParticipantsUpdate = (action) => ev.emit('group-participants.update', {
|
|
383
|
+
id: jid,
|
|
384
|
+
author: message.key.participant,
|
|
385
|
+
authorPn: message.key.participantAlt,
|
|
386
|
+
participants,
|
|
387
|
+
action
|
|
388
|
+
});
|
|
219
389
|
const emitGroupUpdate = (update) => {
|
|
220
|
-
|
|
221
|
-
|
|
390
|
+
ev.emit('groups.update', [
|
|
391
|
+
{ id: jid, ...update, author: message.key.participant ?? undefined, authorPn: message.key.participantAlt }
|
|
392
|
+
]);
|
|
393
|
+
};
|
|
394
|
+
const emitGroupRequestJoin = (participant, action, method) => {
|
|
395
|
+
ev.emit('group.join-request', {
|
|
396
|
+
id: jid,
|
|
397
|
+
author: message.key.participant,
|
|
398
|
+
authorPn: message.key.participantAlt,
|
|
399
|
+
participant: participant.lid,
|
|
400
|
+
participantPn: participant.pn,
|
|
401
|
+
action,
|
|
402
|
+
method: method
|
|
403
|
+
});
|
|
222
404
|
};
|
|
223
|
-
const participantsIncludesMe = () => participants.find(jid =>
|
|
405
|
+
const participantsIncludesMe = () => participants.find(jid => areJidsSameUser(meId, jid.phoneNumber)); // ADD SUPPORT FOR LID
|
|
224
406
|
switch (message.messageStubType) {
|
|
225
|
-
case
|
|
226
|
-
|
|
227
|
-
|
|
407
|
+
case WAMessageStubType.GROUP_PARTICIPANT_CHANGE_NUMBER:
|
|
408
|
+
participants = message.messageStubParameters.map((a) => JSON.parse(a)) || [];
|
|
409
|
+
emitParticipantsUpdate('modify');
|
|
410
|
+
break;
|
|
411
|
+
case WAMessageStubType.GROUP_PARTICIPANT_LEAVE:
|
|
412
|
+
case WAMessageStubType.GROUP_PARTICIPANT_REMOVE:
|
|
413
|
+
participants = message.messageStubParameters.map((a) => JSON.parse(a)) || [];
|
|
228
414
|
emitParticipantsUpdate('remove');
|
|
229
415
|
// mark the chat read only if you left the group
|
|
230
416
|
if (participantsIncludesMe()) {
|
|
231
417
|
chat.readOnly = true;
|
|
232
418
|
}
|
|
233
419
|
break;
|
|
234
|
-
case
|
|
235
|
-
case
|
|
236
|
-
case
|
|
237
|
-
participants = message.messageStubParameters || [];
|
|
420
|
+
case WAMessageStubType.GROUP_PARTICIPANT_ADD:
|
|
421
|
+
case WAMessageStubType.GROUP_PARTICIPANT_INVITE:
|
|
422
|
+
case WAMessageStubType.GROUP_PARTICIPANT_ADD_REQUEST_JOIN:
|
|
423
|
+
participants = message.messageStubParameters.map((a) => JSON.parse(a)) || [];
|
|
238
424
|
if (participantsIncludesMe()) {
|
|
239
425
|
chat.readOnly = false;
|
|
240
426
|
}
|
|
241
427
|
emitParticipantsUpdate('add');
|
|
242
428
|
break;
|
|
243
|
-
case
|
|
244
|
-
participants = message.messageStubParameters || [];
|
|
429
|
+
case WAMessageStubType.GROUP_PARTICIPANT_DEMOTE:
|
|
430
|
+
participants = message.messageStubParameters.map((a) => JSON.parse(a)) || [];
|
|
245
431
|
emitParticipantsUpdate('demote');
|
|
246
432
|
break;
|
|
247
|
-
case
|
|
248
|
-
participants = message.messageStubParameters || [];
|
|
433
|
+
case WAMessageStubType.GROUP_PARTICIPANT_PROMOTE:
|
|
434
|
+
participants = message.messageStubParameters.map((a) => JSON.parse(a)) || [];
|
|
249
435
|
emitParticipantsUpdate('promote');
|
|
250
436
|
break;
|
|
251
|
-
case
|
|
252
|
-
const announceValue =
|
|
437
|
+
case WAMessageStubType.GROUP_CHANGE_ANNOUNCE:
|
|
438
|
+
const announceValue = message.messageStubParameters?.[0];
|
|
253
439
|
emitGroupUpdate({ announce: announceValue === 'true' || announceValue === 'on' });
|
|
254
440
|
break;
|
|
255
|
-
case
|
|
256
|
-
const restrictValue =
|
|
441
|
+
case WAMessageStubType.GROUP_CHANGE_RESTRICT:
|
|
442
|
+
const restrictValue = message.messageStubParameters?.[0];
|
|
257
443
|
emitGroupUpdate({ restrict: restrictValue === 'true' || restrictValue === 'on' });
|
|
258
444
|
break;
|
|
259
|
-
case
|
|
260
|
-
const name =
|
|
445
|
+
case WAMessageStubType.GROUP_CHANGE_SUBJECT:
|
|
446
|
+
const name = message.messageStubParameters?.[0];
|
|
261
447
|
chat.name = name;
|
|
262
448
|
emitGroupUpdate({ subject: name });
|
|
263
449
|
break;
|
|
264
|
-
case
|
|
265
|
-
const
|
|
450
|
+
case WAMessageStubType.GROUP_CHANGE_DESCRIPTION:
|
|
451
|
+
const description = message.messageStubParameters?.[0];
|
|
452
|
+
chat.description = description;
|
|
453
|
+
emitGroupUpdate({ desc: description });
|
|
454
|
+
break;
|
|
455
|
+
case WAMessageStubType.GROUP_CHANGE_INVITE_LINK:
|
|
456
|
+
const code = message.messageStubParameters?.[0];
|
|
266
457
|
emitGroupUpdate({ inviteCode: code });
|
|
267
458
|
break;
|
|
268
|
-
case
|
|
269
|
-
const memberAddValue =
|
|
459
|
+
case WAMessageStubType.GROUP_MEMBER_ADD_MODE:
|
|
460
|
+
const memberAddValue = message.messageStubParameters?.[0];
|
|
270
461
|
emitGroupUpdate({ memberAddMode: memberAddValue === 'all_member_add' });
|
|
271
462
|
break;
|
|
272
|
-
case
|
|
273
|
-
const approvalMode =
|
|
463
|
+
case WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_MODE:
|
|
464
|
+
const approvalMode = message.messageStubParameters?.[0];
|
|
274
465
|
emitGroupUpdate({ joinApprovalMode: approvalMode === 'on' });
|
|
275
466
|
break;
|
|
467
|
+
case WAMessageStubType.GROUP_MEMBERSHIP_JOIN_APPROVAL_REQUEST_NON_ADMIN_ADD: // TODO: Add other events
|
|
468
|
+
const participant = JSON.parse(message.messageStubParameters?.[0]);
|
|
469
|
+
const action = message.messageStubParameters?.[1];
|
|
470
|
+
const method = message.messageStubParameters?.[2];
|
|
471
|
+
emitGroupRequestJoin(participant, action, method);
|
|
472
|
+
break;
|
|
276
473
|
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
const creationMsgKey = content.pollUpdateMessage.pollCreationMessageKey;
|
|
474
|
+
} /* else if(content?.pollUpdateMessage) {
|
|
475
|
+
const creationMsgKey = content.pollUpdateMessage.pollCreationMessageKey!
|
|
280
476
|
// we need to fetch the poll creation message to get the poll enc key
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
const
|
|
286
|
-
const
|
|
477
|
+
// TODO: make standalone, remove getMessage reference
|
|
478
|
+
// TODO: Remove entirely
|
|
479
|
+
const pollMsg = await getMessage(creationMsgKey)
|
|
480
|
+
if(pollMsg) {
|
|
481
|
+
const meIdNormalised = jidNormalizedUser(meId)
|
|
482
|
+
const pollCreatorJid = getKeyAuthor(creationMsgKey, meIdNormalised)
|
|
483
|
+
const voterJid = getKeyAuthor(message.key, meIdNormalised)
|
|
484
|
+
const pollEncKey = pollMsg.messageContextInfo?.messageSecret!
|
|
485
|
+
|
|
287
486
|
try {
|
|
288
|
-
const voteMsg = decryptPollVote(
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
487
|
+
const voteMsg = decryptPollVote(
|
|
488
|
+
content.pollUpdateMessage.vote!,
|
|
489
|
+
{
|
|
490
|
+
pollEncKey,
|
|
491
|
+
pollCreatorJid,
|
|
492
|
+
pollMsgId: creationMsgKey.id!,
|
|
493
|
+
voterJid,
|
|
494
|
+
}
|
|
495
|
+
)
|
|
294
496
|
ev.emit('messages.update', [
|
|
295
497
|
{
|
|
296
498
|
key: creationMsgKey,
|
|
@@ -299,23 +501,27 @@ const processMessage = async (message, { shouldProcessHistoryMsg, ev, creds, key
|
|
|
299
501
|
{
|
|
300
502
|
pollUpdateMessageKey: message.key,
|
|
301
503
|
vote: voteMsg,
|
|
302
|
-
senderTimestampMs: content.pollUpdateMessage.senderTimestampMs.toNumber(),
|
|
504
|
+
senderTimestampMs: (content.pollUpdateMessage.senderTimestampMs! as Long).toNumber(),
|
|
303
505
|
}
|
|
304
506
|
]
|
|
305
507
|
}
|
|
306
508
|
}
|
|
307
|
-
])
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
|
|
509
|
+
])
|
|
510
|
+
} catch(err) {
|
|
511
|
+
logger?.warn(
|
|
512
|
+
{ err, creationMsgKey },
|
|
513
|
+
'failed to decrypt poll vote'
|
|
514
|
+
)
|
|
311
515
|
}
|
|
516
|
+
} else {
|
|
517
|
+
logger?.warn(
|
|
518
|
+
{ creationMsgKey },
|
|
519
|
+
'poll creation message not found, cannot decrypt update'
|
|
520
|
+
)
|
|
312
521
|
}
|
|
313
|
-
|
|
314
|
-
logger === null || logger === void 0 ? void 0 : logger.warn({ creationMsgKey }, 'poll creation message not found, cannot decrypt update');
|
|
315
|
-
}
|
|
316
|
-
}
|
|
522
|
+
} */
|
|
317
523
|
if (Object.keys(chat).length > 1) {
|
|
318
524
|
ev.emit('chats.update', [chat]);
|
|
319
525
|
}
|
|
320
526
|
};
|
|
321
|
-
|
|
527
|
+
export default processMessage;
|