@queenanya/baileys 9.2.1 → 9.5.1
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 +531 -445
- package/WAProto/fix-imports.js +70 -18
- package/WAProto/index.js +197 -160
- package/engine-requirements.js +7 -7
- package/lib/Defaults/index.d.ts +12 -0
- package/lib/Defaults/index.d.ts.map +1 -1
- package/lib/Defaults/index.js +17 -5
- package/lib/Defaults/index.js.map +1 -1
- package/lib/Signal/libsignal.d.ts.map +1 -1
- package/lib/Signal/libsignal.js +63 -2
- package/lib/Signal/libsignal.js.map +1 -1
- package/lib/Signal/lid-mapping.d.ts +5 -9
- package/lib/Signal/lid-mapping.d.ts.map +1 -1
- package/lib/Signal/lid-mapping.js +170 -70
- package/lib/Signal/lid-mapping.js.map +1 -1
- package/lib/Socket/Client/websocket.d.ts +1 -1
- package/lib/Socket/Client/websocket.d.ts.map +1 -1
- package/lib/Socket/Client/websocket.js +5 -1
- package/lib/Socket/Client/websocket.js.map +1 -1
- package/lib/Socket/business.d.ts +16 -4
- package/lib/Socket/business.d.ts.map +1 -1
- package/lib/Socket/business.js +11 -8
- package/lib/Socket/business.js.map +1 -1
- package/lib/Socket/chats.d.ts +14 -3
- package/lib/Socket/chats.d.ts.map +1 -1
- package/lib/Socket/chats.js +55 -28
- package/lib/Socket/chats.js.map +1 -1
- package/lib/Socket/communities.d.ts +16 -4
- package/lib/Socket/communities.d.ts.map +1 -1
- package/lib/Socket/groups.d.ts +14 -3
- package/lib/Socket/groups.d.ts.map +1 -1
- package/lib/Socket/groups.js +1 -1
- package/lib/Socket/groups.js.map +1 -1
- package/lib/Socket/index.d.ts +16 -4
- package/lib/Socket/index.d.ts.map +1 -1
- package/lib/Socket/index.js +0 -6
- package/lib/Socket/index.js.map +1 -1
- package/lib/Socket/messages-recv.d.ts +16 -4
- package/lib/Socket/messages-recv.d.ts.map +1 -1
- package/lib/Socket/messages-recv.js +152 -87
- package/lib/Socket/messages-recv.js.map +1 -1
- package/lib/Socket/messages-send.d.ts +15 -3
- package/lib/Socket/messages-send.d.ts.map +1 -1
- package/lib/Socket/messages-send.js +117 -48
- package/lib/Socket/messages-send.js.map +1 -1
- package/lib/Socket/newsletter.d.ts +15 -5
- package/lib/Socket/newsletter.d.ts.map +1 -1
- package/lib/Socket/newsletter.js +2 -47
- package/lib/Socket/newsletter.js.map +1 -1
- package/lib/Socket/socket.d.ts +3 -1
- package/lib/Socket/socket.d.ts.map +1 -1
- package/lib/Socket/socket.js +71 -16
- package/lib/Socket/socket.js.map +1 -1
- package/lib/Types/Auth.d.ts +1 -0
- package/lib/Types/Auth.d.ts.map +1 -1
- package/lib/Types/Call.d.ts +1 -0
- package/lib/Types/Call.d.ts.map +1 -1
- package/lib/Types/Events.d.ts +40 -5
- package/lib/Types/Events.d.ts.map +1 -1
- package/lib/Types/Message.d.ts +3 -3
- package/lib/Types/Message.d.ts.map +1 -1
- package/lib/Types/Newsletter.d.ts +0 -17
- package/lib/Types/Newsletter.d.ts.map +1 -1
- package/lib/Utils/auth-utils.d.ts.map +1 -1
- package/lib/Utils/auth-utils.js +53 -20
- package/lib/Utils/auth-utils.js.map +1 -1
- package/lib/Utils/chat-utils.d.ts.map +1 -1
- package/lib/Utils/chat-utils.js +100 -51
- package/lib/Utils/chat-utils.js.map +1 -1
- package/lib/Utils/crypto.d.ts +4 -8
- package/lib/Utils/crypto.d.ts.map +1 -1
- package/lib/Utils/crypto.js +2 -26
- package/lib/Utils/crypto.js.map +1 -1
- package/lib/Utils/event-buffer.d.ts.map +1 -1
- package/lib/Utils/event-buffer.js +33 -7
- package/lib/Utils/event-buffer.js.map +1 -1
- package/lib/Utils/generics.d.ts +1 -0
- package/lib/Utils/generics.d.ts.map +1 -1
- package/lib/Utils/generics.js +5 -2
- package/lib/Utils/generics.js.map +1 -1
- package/lib/Utils/history.d.ts +6 -3
- package/lib/Utils/history.d.ts.map +1 -1
- package/lib/Utils/history.js +46 -5
- package/lib/Utils/history.js.map +1 -1
- package/lib/Utils/identity-change-handler.d.ts +37 -0
- package/lib/Utils/identity-change-handler.d.ts.map +1 -0
- package/lib/Utils/identity-change-handler.js +49 -0
- package/lib/Utils/identity-change-handler.js.map +1 -0
- package/lib/Utils/index.d.ts +1 -0
- package/lib/Utils/index.d.ts.map +1 -1
- package/lib/Utils/index.js +1 -0
- package/lib/Utils/index.js.map +1 -1
- package/lib/Utils/lt-hash.d.ts +7 -12
- package/lib/Utils/lt-hash.d.ts.map +1 -1
- package/lib/Utils/lt-hash.js +2 -42
- package/lib/Utils/lt-hash.js.map +1 -1
- package/lib/Utils/make-mutex.d.ts +1 -0
- package/lib/Utils/make-mutex.d.ts.map +1 -1
- package/lib/Utils/make-mutex.js +20 -27
- package/lib/Utils/make-mutex.js.map +1 -1
- package/lib/Utils/message-retry-manager.d.ts +30 -2
- package/lib/Utils/message-retry-manager.d.ts.map +1 -1
- package/lib/Utils/message-retry-manager.js +58 -5
- package/lib/Utils/message-retry-manager.js.map +1 -1
- package/lib/Utils/messages-media.d.ts +18 -2
- package/lib/Utils/messages-media.d.ts.map +1 -1
- package/lib/Utils/messages-media.js +150 -39
- package/lib/Utils/messages-media.js.map +1 -1
- package/lib/Utils/messages.d.ts +2 -0
- package/lib/Utils/messages.d.ts.map +1 -1
- package/lib/Utils/messages.js +41 -23
- package/lib/Utils/messages.js.map +1 -1
- package/lib/Utils/noise-handler.d.ts +4 -4
- package/lib/Utils/noise-handler.d.ts.map +1 -1
- package/lib/Utils/noise-handler.js +139 -85
- package/lib/Utils/noise-handler.js.map +1 -1
- package/lib/Utils/process-message.d.ts.map +1 -1
- package/lib/Utils/process-message.js +57 -14
- package/lib/Utils/process-message.js.map +1 -1
- package/lib/Utils/reporting-utils.d.ts +11 -0
- package/lib/Utils/reporting-utils.d.ts.map +1 -0
- package/lib/Utils/reporting-utils.js +258 -0
- package/lib/Utils/reporting-utils.js.map +1 -0
- package/lib/Utils/sync-action-utils.d.ts +19 -0
- package/lib/Utils/sync-action-utils.d.ts.map +1 -0
- package/lib/Utils/sync-action-utils.js +48 -0
- package/lib/Utils/sync-action-utils.js.map +1 -0
- package/lib/Utils/tc-token-utils.d.ts +12 -0
- package/lib/Utils/tc-token-utils.d.ts.map +1 -0
- package/lib/Utils/tc-token-utils.js +18 -0
- package/lib/Utils/tc-token-utils.js.map +1 -0
- package/lib/Utils/use-multi-file-auth-state.js +1 -1
- package/lib/Utils/use-multi-file-auth-state.js.map +1 -1
- package/lib/Utils/use-single-file-auth-state.d.ts.map +1 -1
- package/lib/Utils/use-single-file-auth-state.js.map +1 -1
- package/lib/WABinary/decode.d.ts.map +1 -1
- package/lib/WABinary/decode.js +24 -0
- package/lib/WABinary/decode.js.map +1 -1
- package/lib/WABinary/encode.js +5 -1
- package/lib/WABinary/encode.js.map +1 -1
- package/lib/WABinary/generic-utils.d.ts +1 -1
- package/lib/WABinary/generic-utils.d.ts.map +1 -1
- package/lib/WABinary/generic-utils.js +19 -8
- package/lib/WABinary/generic-utils.js.map +1 -1
- package/lib/WABinary/jid-utils.d.ts +0 -3
- package/lib/WABinary/jid-utils.d.ts.map +1 -1
- package/lib/WABinary/jid-utils.js +0 -4
- package/lib/WABinary/jid-utils.js.map +1 -1
- package/package.json +4 -2
|
@@ -8,7 +8,7 @@ export declare const makeMessagesRecvSocket: (config: SocketConfig) => {
|
|
|
8
8
|
sendRetryRequest: (node: BinaryNode, forceIncludeKeys?: boolean) => Promise<void>;
|
|
9
9
|
rejectCall: (callId: string, callFrom: string) => Promise<void>;
|
|
10
10
|
fetchMessageHistory: (count: number, oldestMsgKey: WAMessageKey, oldestMsgTimestamp: number | Long) => Promise<string>;
|
|
11
|
-
requestPlaceholderResend: (messageKey: WAMessageKey) => Promise<string | undefined>;
|
|
11
|
+
requestPlaceholderResend: (messageKey: WAMessageKey, msgData?: Partial<WAMessage>) => Promise<string | undefined>;
|
|
12
12
|
messageRetryManager: import("../Utils/index.js").MessageRetryManager | null;
|
|
13
13
|
getPrivacyTokens: (jids: string[]) => Promise<any>;
|
|
14
14
|
assertSessions: (jids: string[], force?: boolean) => Promise<boolean>;
|
|
@@ -29,6 +29,7 @@ export declare const makeMessagesRecvSocket: (config: SocketConfig) => {
|
|
|
29
29
|
getUSyncDevices: (jids: string[], useCache: boolean, ignoreZeroDevices: boolean) => Promise<(import("../WABinary/index.js").JidWithDevice & {
|
|
30
30
|
jid: string;
|
|
31
31
|
})[]>;
|
|
32
|
+
updateMemberLabel: (jid: string, memberLabel: string) => Promise<string>;
|
|
32
33
|
updateMediaMessage: (message: WAMessage) => Promise<WAMessage>;
|
|
33
34
|
sendMessage: (jid: string, content: import("../Types/index.js").AnyMessageContent, options?: import("../Types/index.js").MiscMessageGenerationOptions) => Promise<WAMessage | undefined>;
|
|
34
35
|
newsletterCreate: (name: string, description?: string) => Promise<import("../Types/index.js").NewsletterMetadata>;
|
|
@@ -89,13 +90,22 @@ export declare const makeMessagesRecvSocket: (config: SocketConfig) => {
|
|
|
89
90
|
startTime: number;
|
|
90
91
|
}, timeoutMs?: number) => Promise<string | undefined>;
|
|
91
92
|
getBotListV2: () => Promise<import("../Types/index.js").BotListInfo[]>;
|
|
92
|
-
|
|
93
|
+
messageMutex: {
|
|
94
|
+
mutex<T>(code: () => Promise<T> | T): Promise<T>;
|
|
95
|
+
};
|
|
96
|
+
receiptMutex: {
|
|
97
|
+
mutex<T>(code: () => Promise<T> | T): Promise<T>;
|
|
98
|
+
};
|
|
99
|
+
appStatePatchMutex: {
|
|
100
|
+
mutex<T>(code: () => Promise<T> | T): Promise<T>;
|
|
101
|
+
};
|
|
102
|
+
notificationMutex: {
|
|
93
103
|
mutex<T>(code: () => Promise<T> | T): Promise<T>;
|
|
94
104
|
};
|
|
95
105
|
upsertMessage: (msg: WAMessage, type: import("../Types/index.js").MessageUpsertType) => Promise<void>;
|
|
96
106
|
appPatch: (patchCreate: import("../Types/index.js").WAPatchCreate) => Promise<void>;
|
|
97
107
|
sendPresenceUpdate: (type: import("../Types/index.js").WAPresence, toJid?: string) => Promise<void>;
|
|
98
|
-
presenceSubscribe: (toJid: string
|
|
108
|
+
presenceSubscribe: (toJid: string) => Promise<void>;
|
|
99
109
|
profilePictureUrl: (jid: string, type?: "preview" | "image", timeoutMs?: number) => Promise<string | undefined>;
|
|
100
110
|
fetchBlocklist: () => Promise<(string | undefined)[]>;
|
|
101
111
|
fetchStatus: (...jids: string[]) => Promise<import("../index.js").USyncQueryResultList[] | undefined>;
|
|
@@ -157,13 +167,15 @@ export declare const makeMessagesRecvSocket: (config: SocketConfig) => {
|
|
|
157
167
|
sendRawMessage: (data: Uint8Array | Buffer) => Promise<void>;
|
|
158
168
|
sendNode: (frame: BinaryNode) => Promise<void>;
|
|
159
169
|
logout: (msg?: string) => Promise<void>;
|
|
160
|
-
end: (error: Error | undefined) => void
|
|
170
|
+
end: (error: Error | undefined) => Promise<void>;
|
|
161
171
|
onUnexpectedError: (err: Error | Boom, msg: string) => void;
|
|
162
172
|
uploadPreKeys: (count?: number, retryCount?: number) => Promise<void>;
|
|
163
173
|
uploadPreKeysToServerIfRequired: () => Promise<void>;
|
|
164
174
|
digestKeyBundle: () => Promise<void>;
|
|
165
175
|
rotateSignedPreKey: () => Promise<void>;
|
|
166
176
|
requestPairingCode: (phoneNumber: string, customPairingCode?: string) => Promise<string>;
|
|
177
|
+
updateServerTimeOffset: ({ attrs }: BinaryNode) => void;
|
|
178
|
+
sendUnifiedSession: () => Promise<void>;
|
|
167
179
|
wamBuffer: import("../index.js").BinaryInfo;
|
|
168
180
|
waitForConnectionUpdate: (check: (u: Partial<import("../Types/index.js").ConnectionState>) => Promise<boolean | undefined>, timeoutMs?: number) => Promise<void>;
|
|
169
181
|
sendWAMBuffer: (wamBuffer: Buffer) => Promise<any>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages-recv.d.ts","sourceRoot":"","sources":["../../src/Socket/messages-recv.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEjC,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;
|
|
1
|
+
{"version":3,"file":"messages-recv.d.ts","sourceRoot":"","sources":["../../src/Socket/messages-recv.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAEjC,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAQ9C,OAAO,KAAK,EAEX,kBAAkB,EAClB,mBAAmB,EAEnB,YAAY,EAEZ,SAAS,EACT,YAAY,EAEZ,MAAM,UAAU,CAAA;AA8BjB,OAAO,EAEN,KAAK,UAAU,EAef,MAAM,aAAa,CAAA;AAIpB,eAAO,MAAM,sBAAsB,GAAI,QAAQ,YAAY;8CA+QH,UAAU,cAAc,MAAM;6BA2D/C,UAAU;yBAtBd,MAAM,YAAY,MAAM;iCA9PlD,MAAM,gBACC,YAAY,sBACN,MAAM,GAAG,IAAI,KAC/B,OAAO,CAAC,MAAM,CAAC;2CAoBL,YAAY,YACd,OAAO,CAAC,SAAS,CAAC,KAC1B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAipBzB,CAAC;;;;;;;;;0DAhuBuD,GAAG,0BACxC,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyjD3B,CAAA"}
|
|
@@ -3,9 +3,9 @@ import { Boom } from '@hapi/boom';
|
|
|
3
3
|
import { randomBytes } from 'crypto';
|
|
4
4
|
import Long from 'long';
|
|
5
5
|
import { proto } from '../../WAProto/index.js';
|
|
6
|
-
import { DEFAULT_CACHE_TTLS, KEY_BUNDLE_TYPE, MIN_PREKEY_COUNT } from '../Defaults/index.js';
|
|
6
|
+
import { DEFAULT_CACHE_TTLS, KEY_BUNDLE_TYPE, MIN_PREKEY_COUNT, PLACEHOLDER_MAX_AGE_SECONDS, STATUS_EXPIRY_SECONDS } from '../Defaults/index.js';
|
|
7
7
|
import { WAMessageStatus, WAMessageStubType } from '../Types/index.js';
|
|
8
|
-
import { aesDecryptCTR, aesEncryptGCM, cleanMessage, Curve, decodeMediaRetryNode, decodeMessageNode, decryptMessageNode, delay, derivePairingCodeKey, encodeBigEndian, encodeSignedDeviceIdentity, extractAddressingContext, getCallStatusFromNode, getHistoryMsg, getNextPreKeys, getStatusFromReceiptType, hkdf, MISSING_KEYS_ERROR_TEXT, NACK_REASONS, unixTimestampSeconds, xmppPreKey, xmppSignedPreKey } from '../Utils/index.js';
|
|
8
|
+
import { aesDecryptCTR, aesEncryptGCM, cleanMessage, Curve, decodeMediaRetryNode, decodeMessageNode, decryptMessageNode, delay, derivePairingCodeKey, encodeBigEndian, encodeSignedDeviceIdentity, extractAddressingContext, getCallStatusFromNode, getHistoryMsg, getNextPreKeys, getStatusFromReceiptType, handleIdentityChange, hkdf, MISSING_KEYS_ERROR_TEXT, NACK_REASONS, NO_MESSAGE_FOUND_ERROR_TEXT, toNumber, unixTimestampSeconds, xmppPreKey, xmppSignedPreKey } from '../Utils/index.js';
|
|
9
9
|
import { makeMutex } from '../Utils/make-mutex.js';
|
|
10
10
|
import { areJidsSameUser, binaryNodeToString, getAllBinaryNodeChildren, getBinaryNodeChild, getBinaryNodeChildBuffer, getBinaryNodeChildren, getBinaryNodeChildString, isJidGroup, isJidNewsletter, isJidStatusBroadcast, isLidUser, isPnUser, jidDecode, jidNormalizedUser, S_WHATSAPP_NET } from '../WABinary/index.js';
|
|
11
11
|
import { extractGroupMetadata } from './groups.js';
|
|
@@ -13,7 +13,7 @@ import { makeMessagesSocket } from './messages-send.js';
|
|
|
13
13
|
export const makeMessagesRecvSocket = (config) => {
|
|
14
14
|
const { logger, retryRequestDelayMs, maxMsgRetryCount, getMessage, shouldIgnoreJid, enableAutoSessionRecreation } = config;
|
|
15
15
|
const sock = makeMessagesSocket(config);
|
|
16
|
-
const { ev, authState, ws,
|
|
16
|
+
const { ev, authState, ws, messageMutex, notificationMutex, receiptMutex, signalRepository, query, upsertMessage, resyncAppState, onUnexpectedError, assertSessions, sendNode, relayMessage, sendReceipt, uploadPreKeys, sendPeerDataOperationMessage, messageRetryManager } = sock;
|
|
17
17
|
/** this mutex ensures that each retryRequest will wait for the previous one to finish */
|
|
18
18
|
const retryMutex = makeMutex();
|
|
19
19
|
const msgRetryCache = config.msgRetryCounterCache ||
|
|
@@ -50,19 +50,21 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
50
50
|
};
|
|
51
51
|
return sendPeerDataOperationMessage(pdoMessage);
|
|
52
52
|
};
|
|
53
|
-
const requestPlaceholderResend = async (messageKey) => {
|
|
53
|
+
const requestPlaceholderResend = async (messageKey, msgData) => {
|
|
54
54
|
if (!authState.creds.me?.id) {
|
|
55
55
|
throw new Boom('Not authenticated');
|
|
56
56
|
}
|
|
57
|
-
if (placeholderResendCache.get(messageKey?.id)) {
|
|
57
|
+
if (await placeholderResendCache.get(messageKey?.id)) {
|
|
58
58
|
logger.debug({ messageKey }, 'already requested resend');
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
61
|
else {
|
|
62
|
-
|
|
62
|
+
// Store original message data so PDO response handler can preserve
|
|
63
|
+
// metadata (LID details, timestamps, etc.) that the phone may omit
|
|
64
|
+
await placeholderResendCache.set(messageKey?.id, msgData || true);
|
|
63
65
|
}
|
|
64
|
-
await delay(
|
|
65
|
-
if (!placeholderResendCache.get(messageKey?.id)) {
|
|
66
|
+
await delay(2000);
|
|
67
|
+
if (!(await placeholderResendCache.get(messageKey?.id))) {
|
|
66
68
|
logger.debug({ messageKey }, 'message received while resend requested');
|
|
67
69
|
return 'RESOLVED';
|
|
68
70
|
}
|
|
@@ -75,11 +77,11 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
75
77
|
peerDataOperationRequestType: proto.Message.PeerDataOperationRequestType.PLACEHOLDER_MESSAGE_RESEND
|
|
76
78
|
};
|
|
77
79
|
setTimeout(async () => {
|
|
78
|
-
if (placeholderResendCache.get(messageKey?.id)) {
|
|
79
|
-
logger.debug({ messageKey }, 'PDO message without response after
|
|
80
|
+
if (await placeholderResendCache.get(messageKey?.id)) {
|
|
81
|
+
logger.debug({ messageKey }, 'PDO message without response after 8 seconds. Phone possibly offline');
|
|
80
82
|
await placeholderResendCache.del(messageKey?.id);
|
|
81
83
|
}
|
|
82
|
-
},
|
|
84
|
+
}, 8000);
|
|
83
85
|
return sendPeerDataOperationMessage(pdoMessage);
|
|
84
86
|
};
|
|
85
87
|
// Handles mex newsletter notifications
|
|
@@ -300,12 +302,12 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
300
302
|
// Check if we should recreate the session
|
|
301
303
|
let shouldRecreateSession = false;
|
|
302
304
|
let recreateReason = '';
|
|
303
|
-
if (enableAutoSessionRecreation && messageRetryManager) {
|
|
305
|
+
if (enableAutoSessionRecreation && messageRetryManager && retryCount > 1) {
|
|
304
306
|
try {
|
|
305
307
|
// Check if we have a session with this JID
|
|
306
308
|
const sessionId = signalRepository.jidToSignalProtocolAddress(fromJid);
|
|
307
309
|
const hasSession = await signalRepository.validateSession(fromJid);
|
|
308
|
-
const result = messageRetryManager.shouldRecreateSession(fromJid,
|
|
310
|
+
const result = messageRetryManager.shouldRecreateSession(fromJid, hasSession.exists);
|
|
309
311
|
shouldRecreateSession = result.recreate;
|
|
310
312
|
recreateReason = result.reason;
|
|
311
313
|
if (shouldRecreateSession) {
|
|
@@ -407,22 +409,15 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
407
409
|
}
|
|
408
410
|
}
|
|
409
411
|
else {
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
await assertSessions([from], true);
|
|
420
|
-
}
|
|
421
|
-
catch (error) {
|
|
422
|
-
logger.warn({ error, jid: from }, 'failed to assert sessions after identity change');
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
else {
|
|
412
|
+
const result = await handleIdentityChange(node, {
|
|
413
|
+
meId: authState.creds.me?.id,
|
|
414
|
+
meLid: authState.creds.me?.lid,
|
|
415
|
+
validateSession: signalRepository.validateSession,
|
|
416
|
+
assertSessions,
|
|
417
|
+
debounceCache: identityAssertDebounce,
|
|
418
|
+
logger
|
|
419
|
+
});
|
|
420
|
+
if (result.action === 'no_identity_node') {
|
|
426
421
|
logger.info({ node }, 'unknown encrypt notification');
|
|
427
422
|
}
|
|
428
423
|
}
|
|
@@ -556,19 +551,6 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
556
551
|
const nodeType = node.attrs.type;
|
|
557
552
|
const from = jidNormalizedUser(node.attrs.from);
|
|
558
553
|
switch (nodeType) {
|
|
559
|
-
case 'privacy_token':
|
|
560
|
-
const tokenList = getBinaryNodeChildren(child, 'token');
|
|
561
|
-
for (const { attrs, content } of tokenList) {
|
|
562
|
-
const jid = attrs.jid;
|
|
563
|
-
ev.emit('chats.update', [
|
|
564
|
-
{
|
|
565
|
-
id: jid,
|
|
566
|
-
tcToken: content
|
|
567
|
-
}
|
|
568
|
-
]);
|
|
569
|
-
logger.debug({ jid }, 'got privacy token update');
|
|
570
|
-
}
|
|
571
|
-
break;
|
|
572
554
|
case 'newsletter':
|
|
573
555
|
await handleNewsletterNotification(node);
|
|
574
556
|
break;
|
|
@@ -605,6 +587,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
605
587
|
case 'picture':
|
|
606
588
|
const setPicture = getBinaryNodeChild(node, 'set');
|
|
607
589
|
const delPicture = getBinaryNodeChild(node, 'delete');
|
|
590
|
+
// TODO: WAJIDHASH stuff proper support inhouse
|
|
608
591
|
ev.emit('contacts.update', [
|
|
609
592
|
{
|
|
610
593
|
id: jidNormalizedUser(node?.attrs?.from) || (setPicture || delPicture)?.attrs?.hash || '',
|
|
@@ -657,7 +640,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
657
640
|
const companionSharedKey = Curve.sharedKey(authState.creds.pairingEphemeralKeyPair.private, codePairingPublicKey);
|
|
658
641
|
const random = randomBytes(32);
|
|
659
642
|
const linkCodeSalt = randomBytes(32);
|
|
660
|
-
const linkCodePairingExpanded =
|
|
643
|
+
const linkCodePairingExpanded = hkdf(companionSharedKey, 32, {
|
|
661
644
|
salt: linkCodeSalt,
|
|
662
645
|
info: 'link_code_pairing_key_bundle_encryption_key'
|
|
663
646
|
});
|
|
@@ -671,7 +654,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
671
654
|
const encryptedPayload = Buffer.concat([linkCodeSalt, encryptIv, encrypted]);
|
|
672
655
|
const identitySharedKey = Curve.sharedKey(authState.creds.signedIdentityKey.private, primaryIdentityPublicKey);
|
|
673
656
|
const identityPayload = Buffer.concat([companionSharedKey, identitySharedKey, random]);
|
|
674
|
-
authState.creds.advSecretKey = (
|
|
657
|
+
authState.creds.advSecretKey = Buffer.from(hkdf(identityPayload, 32, { info: 'adv_secret' })).toString('base64');
|
|
675
658
|
await query({
|
|
676
659
|
tag: 'iq',
|
|
677
660
|
attrs: {
|
|
@@ -802,11 +785,11 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
802
785
|
// Check if we should recreate session for this retry
|
|
803
786
|
let shouldRecreateSession = false;
|
|
804
787
|
let recreateReason = '';
|
|
805
|
-
if (enableAutoSessionRecreation && messageRetryManager) {
|
|
788
|
+
if (enableAutoSessionRecreation && messageRetryManager && retryCount > 1) {
|
|
806
789
|
try {
|
|
807
790
|
const sessionId = signalRepository.jidToSignalProtocolAddress(participant);
|
|
808
791
|
const hasSession = await signalRepository.validateSession(participant);
|
|
809
|
-
const result = messageRetryManager.shouldRecreateSession(participant,
|
|
792
|
+
const result = messageRetryManager.shouldRecreateSession(participant, hasSession.exists);
|
|
810
793
|
shouldRecreateSession = result.recreate;
|
|
811
794
|
recreateReason = result.reason;
|
|
812
795
|
if (shouldRecreateSession) {
|
|
@@ -869,7 +852,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
869
852
|
}
|
|
870
853
|
try {
|
|
871
854
|
await Promise.all([
|
|
872
|
-
|
|
855
|
+
receiptMutex.mutex(async () => {
|
|
873
856
|
const status = getStatusFromReceiptType(attrs.type);
|
|
874
857
|
if (typeof status !== 'undefined' &&
|
|
875
858
|
// basically, we only want to know when a message from us has been delivered to/read by the other person
|
|
@@ -890,7 +873,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
890
873
|
else {
|
|
891
874
|
ev.emit('messages.update', ids.map(id => ({
|
|
892
875
|
key: { ...key, id },
|
|
893
|
-
update: { status }
|
|
876
|
+
update: { status, messageTimestamp: toNumber(+(attrs.t ?? 0)) }
|
|
894
877
|
})));
|
|
895
878
|
}
|
|
896
879
|
}
|
|
@@ -933,7 +916,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
933
916
|
}
|
|
934
917
|
try {
|
|
935
918
|
await Promise.all([
|
|
936
|
-
|
|
919
|
+
notificationMutex.mutex(async () => {
|
|
937
920
|
const msg = await processNotification(node);
|
|
938
921
|
if (msg) {
|
|
939
922
|
const fromMe = areJidsSameUser(node.attrs.participant || remoteJid, authState.creds.me.id);
|
|
@@ -967,7 +950,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
967
950
|
}
|
|
968
951
|
const encNode = getBinaryNodeChild(node, 'enc');
|
|
969
952
|
// TODO: temporary fix for crashes and issues resulting of failed msmsg decryption
|
|
970
|
-
if (encNode
|
|
953
|
+
if (encNode?.attrs.type === 'msmsg') {
|
|
971
954
|
logger.debug({ key: node.attrs.key }, 'ignored msmsg');
|
|
972
955
|
await sendMessageAck(node, NACK_REASONS.MissingMessageSecret);
|
|
973
956
|
return;
|
|
@@ -997,58 +980,123 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
997
980
|
}, 'Added message to recent cache for retry receipts');
|
|
998
981
|
}
|
|
999
982
|
try {
|
|
1000
|
-
await
|
|
983
|
+
await messageMutex.mutex(async () => {
|
|
1001
984
|
await decrypt();
|
|
1002
985
|
// message failed to decrypt
|
|
1003
986
|
if (msg.messageStubType === proto.WebMessageInfo.StubType.CIPHERTEXT && msg.category !== 'peer') {
|
|
1004
987
|
if (msg?.messageStubParameters?.[0] === MISSING_KEYS_ERROR_TEXT) {
|
|
1005
988
|
return sendMessageAck(node, NACK_REASONS.ParsingError);
|
|
1006
989
|
}
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
990
|
+
if (msg.messageStubParameters?.[0] === NO_MESSAGE_FOUND_ERROR_TEXT) {
|
|
991
|
+
// Message arrived without encryption (e.g. CTWA ads messages).
|
|
992
|
+
// Check if this is eligible for placeholder resend (matching WA Web filters).
|
|
993
|
+
const unavailableNode = getBinaryNodeChild(node, 'unavailable');
|
|
994
|
+
const unavailableType = unavailableNode?.attrs?.type;
|
|
995
|
+
if (unavailableType === 'bot_unavailable_fanout' ||
|
|
996
|
+
unavailableType === 'hosted_unavailable_fanout' ||
|
|
997
|
+
unavailableType === 'view_once_unavailable_fanout') {
|
|
998
|
+
logger.debug({ msgId: msg.key.id, unavailableType }, 'skipping placeholder resend for excluded unavailable type');
|
|
999
|
+
return sendMessageAck(node);
|
|
1000
|
+
}
|
|
1001
|
+
const messageAge = unixTimestampSeconds() - toNumber(msg.messageTimestamp);
|
|
1002
|
+
if (messageAge > PLACEHOLDER_MAX_AGE_SECONDS) {
|
|
1003
|
+
logger.debug({ msgId: msg.key.id, messageAge }, 'skipping placeholder resend for old message');
|
|
1004
|
+
return sendMessageAck(node);
|
|
1005
|
+
}
|
|
1006
|
+
// Request the real content from the phone via placeholder resend PDO.
|
|
1007
|
+
// Upsert the CIPHERTEXT stub as a placeholder (like WA Web's processPlaceholderMsg),
|
|
1008
|
+
// and store the requestId in stubParameters[1] so users can correlate
|
|
1009
|
+
// with the incoming PDO response event.
|
|
1010
|
+
const cleanKey = {
|
|
1011
|
+
remoteJid: msg.key.remoteJid,
|
|
1012
|
+
fromMe: msg.key.fromMe,
|
|
1013
|
+
id: msg.key.id,
|
|
1014
|
+
participant: msg.key.participant
|
|
1015
|
+
};
|
|
1016
|
+
// Cache the original message metadata so the PDO response handler
|
|
1017
|
+
// can preserve key fields (LID details etc.) that the phone may omit
|
|
1018
|
+
const msgData = {
|
|
1019
|
+
key: msg.key,
|
|
1020
|
+
messageTimestamp: msg.messageTimestamp,
|
|
1021
|
+
pushName: msg.pushName,
|
|
1022
|
+
participant: msg.participant,
|
|
1023
|
+
verifiedBizName: msg.verifiedBizName
|
|
1024
|
+
};
|
|
1025
|
+
requestPlaceholderResend(cleanKey, msgData)
|
|
1026
|
+
.then(requestId => {
|
|
1027
|
+
if (requestId && requestId !== 'RESOLVED') {
|
|
1028
|
+
logger.debug({ msgId: msg.key.id, requestId }, 'requested placeholder resend for unavailable message');
|
|
1029
|
+
ev.emit('messages.update', [
|
|
1030
|
+
{
|
|
1031
|
+
key: msg.key,
|
|
1032
|
+
update: { messageStubParameters: [NO_MESSAGE_FOUND_ERROR_TEXT, requestId] }
|
|
1033
|
+
}
|
|
1034
|
+
]);
|
|
1029
1035
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1036
|
+
})
|
|
1037
|
+
.catch(err => {
|
|
1038
|
+
logger.warn({ err, msgId: msg.key.id }, 'failed to request placeholder resend for unavailable message');
|
|
1039
|
+
});
|
|
1040
|
+
await sendMessageAck(node);
|
|
1041
|
+
// Don't return — fall through to upsertMessage so the stub is emitted
|
|
1042
|
+
}
|
|
1043
|
+
else {
|
|
1044
|
+
// Skip retry for expired status messages (>24h old)
|
|
1045
|
+
if (isJidStatusBroadcast(msg.key.remoteJid)) {
|
|
1046
|
+
const messageAge = unixTimestampSeconds() - toNumber(msg.messageTimestamp);
|
|
1047
|
+
if (messageAge > STATUS_EXPIRY_SECONDS) {
|
|
1048
|
+
logger.debug({ msgId: msg.key.id, messageAge, remoteJid: msg.key.remoteJid }, 'skipping retry for expired status message');
|
|
1049
|
+
return sendMessageAck(node);
|
|
1034
1050
|
}
|
|
1035
1051
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1052
|
+
const errorMessage = msg?.messageStubParameters?.[0] || '';
|
|
1053
|
+
const isPreKeyError = errorMessage.includes('PreKey');
|
|
1054
|
+
logger.debug(`[handleMessage] Attempting retry request for failed decryption`);
|
|
1055
|
+
// Handle both pre-key and normal retries in single mutex
|
|
1056
|
+
await retryMutex.mutex(async () => {
|
|
1039
1057
|
try {
|
|
1058
|
+
if (!ws.isOpen) {
|
|
1059
|
+
logger.debug({ node }, 'Connection closed, skipping retry');
|
|
1060
|
+
return;
|
|
1061
|
+
}
|
|
1062
|
+
// Handle pre-key errors with upload and delay
|
|
1063
|
+
if (isPreKeyError) {
|
|
1064
|
+
logger.info({ error: errorMessage }, 'PreKey error detected, uploading and retrying');
|
|
1065
|
+
try {
|
|
1066
|
+
logger.debug('Uploading pre-keys for error recovery');
|
|
1067
|
+
await uploadPreKeys(5);
|
|
1068
|
+
logger.debug('Waiting for server to process new pre-keys');
|
|
1069
|
+
await delay(1000);
|
|
1070
|
+
}
|
|
1071
|
+
catch (uploadErr) {
|
|
1072
|
+
logger.error({ uploadErr }, 'Pre-key upload failed, proceeding with retry anyway');
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1040
1075
|
const encNode = getBinaryNodeChild(node, 'enc');
|
|
1041
1076
|
await sendRetryRequest(node, !encNode);
|
|
1077
|
+
if (retryRequestDelayMs) {
|
|
1078
|
+
await delay(retryRequestDelayMs);
|
|
1079
|
+
}
|
|
1042
1080
|
}
|
|
1043
|
-
catch (
|
|
1044
|
-
logger.error({
|
|
1081
|
+
catch (err) {
|
|
1082
|
+
logger.error({ err, isPreKeyError }, 'Failed to handle retry, attempting basic retry');
|
|
1083
|
+
// Still attempt retry even if pre-key upload failed
|
|
1084
|
+
try {
|
|
1085
|
+
const encNode = getBinaryNodeChild(node, 'enc');
|
|
1086
|
+
await sendRetryRequest(node, !encNode);
|
|
1087
|
+
}
|
|
1088
|
+
catch (retryErr) {
|
|
1089
|
+
logger.error({ retryErr }, 'Failed to send retry after error handling');
|
|
1090
|
+
}
|
|
1045
1091
|
}
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
}
|
|
1092
|
+
await sendMessageAck(node, NACK_REASONS.UnhandledError);
|
|
1093
|
+
});
|
|
1094
|
+
}
|
|
1049
1095
|
}
|
|
1050
1096
|
else {
|
|
1051
|
-
|
|
1097
|
+
if (messageRetryManager && msg.key.id) {
|
|
1098
|
+
messageRetryManager.cancelPendingPhoneRequest(msg.key.id);
|
|
1099
|
+
}
|
|
1052
1100
|
const isNewsletter = isJidNewsletter(msg.key.remoteJid);
|
|
1053
1101
|
if (!isNewsletter) {
|
|
1054
1102
|
// no type in the receipt => message delivered
|
|
@@ -1074,10 +1122,11 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1074
1122
|
const isAnyHistoryMsg = getHistoryMsg(msg.message);
|
|
1075
1123
|
if (isAnyHistoryMsg) {
|
|
1076
1124
|
const jid = jidNormalizedUser(msg.key.remoteJid);
|
|
1077
|
-
await sendReceipt(jid, undefined, [msg.key.id], 'hist_sync');
|
|
1125
|
+
await sendReceipt(jid, undefined, [msg.key.id], 'hist_sync'); // TODO: investigate
|
|
1078
1126
|
}
|
|
1079
1127
|
}
|
|
1080
1128
|
else {
|
|
1129
|
+
await sendMessageAck(node);
|
|
1081
1130
|
logger.debug({ key: msg.key }, 'processed newsletter message without receipts');
|
|
1082
1131
|
}
|
|
1083
1132
|
}
|
|
@@ -1101,6 +1150,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1101
1150
|
const call = {
|
|
1102
1151
|
chatId: attrs.from,
|
|
1103
1152
|
from,
|
|
1153
|
+
callerPn: infoChild.attrs['caller_pn'],
|
|
1104
1154
|
id: callId,
|
|
1105
1155
|
date: new Date(+attrs.t * 1000),
|
|
1106
1156
|
offline: !!attrs.offline,
|
|
@@ -1117,6 +1167,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1117
1167
|
if (existingCall) {
|
|
1118
1168
|
call.isVideo = existingCall.isVideo;
|
|
1119
1169
|
call.isGroup = existingCall.isGroup;
|
|
1170
|
+
call.callerPn = call.callerPn || existingCall.callerPn;
|
|
1120
1171
|
}
|
|
1121
1172
|
// delete data once call has ended
|
|
1122
1173
|
if (status === 'reject' || status === 'accept' || status === 'timeout' || status === 'terminate') {
|
|
@@ -1178,6 +1229,10 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1178
1229
|
return exec(node, false).catch(err => onUnexpectedError(err, identifier));
|
|
1179
1230
|
}
|
|
1180
1231
|
};
|
|
1232
|
+
/** Yields control to the event loop to prevent blocking */
|
|
1233
|
+
const yieldToEventLoop = () => {
|
|
1234
|
+
return new Promise(resolve => setImmediate(resolve));
|
|
1235
|
+
};
|
|
1181
1236
|
const makeOfflineNodeProcessor = () => {
|
|
1182
1237
|
const nodeProcessorMap = new Map([
|
|
1183
1238
|
['message', handleMessage],
|
|
@@ -1187,6 +1242,8 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1187
1242
|
]);
|
|
1188
1243
|
const nodes = [];
|
|
1189
1244
|
let isProcessing = false;
|
|
1245
|
+
// Number of nodes to process before yielding to event loop
|
|
1246
|
+
const BATCH_SIZE = 10;
|
|
1190
1247
|
const enqueue = (type, node) => {
|
|
1191
1248
|
nodes.push({ type, node });
|
|
1192
1249
|
if (isProcessing) {
|
|
@@ -1194,6 +1251,7 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1194
1251
|
}
|
|
1195
1252
|
isProcessing = true;
|
|
1196
1253
|
const promise = async () => {
|
|
1254
|
+
let processedInBatch = 0;
|
|
1197
1255
|
while (nodes.length && ws.isOpen) {
|
|
1198
1256
|
const { type, node } = nodes.shift();
|
|
1199
1257
|
const nodeProcessor = nodeProcessorMap.get(type);
|
|
@@ -1202,6 +1260,13 @@ export const makeMessagesRecvSocket = (config) => {
|
|
|
1202
1260
|
continue;
|
|
1203
1261
|
}
|
|
1204
1262
|
await nodeProcessor(node);
|
|
1263
|
+
processedInBatch++;
|
|
1264
|
+
// Yield to event loop after processing a batch
|
|
1265
|
+
// This prevents blocking the event loop for too long when there are many offline nodes
|
|
1266
|
+
if (processedInBatch >= BATCH_SIZE) {
|
|
1267
|
+
processedInBatch = 0;
|
|
1268
|
+
await yieldToEventLoop();
|
|
1269
|
+
}
|
|
1205
1270
|
}
|
|
1206
1271
|
isProcessing = false;
|
|
1207
1272
|
};
|