zapo-js 1.1.0 → 1.1.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 +5 -1
- package/dist/auth/pairing/WaPairingFlow.js +2 -0
- package/dist/client/WaClient.js +26 -20
- package/dist/client/coordinators/WaIncomingNodeCoordinator.js +1 -1
- package/dist/client/coordinators/WaRetryCoordinator.d.ts +0 -1
- package/dist/client/coordinators/WaRetryCoordinator.js +1 -21
- package/dist/client/messaging/ignore-key.js +4 -2
- package/dist/client/types.d.ts +13 -10
- package/dist/esm/auth/pairing/WaPairingFlow.js +2 -0
- package/dist/esm/client/WaClient.js +26 -20
- package/dist/esm/client/coordinators/WaIncomingNodeCoordinator.js +1 -1
- package/dist/esm/client/coordinators/WaRetryCoordinator.js +1 -21
- package/dist/esm/client/messaging/ignore-key.js +4 -2
- package/dist/esm/message/primitives/incoming.js +6 -2
- package/dist/esm/transport/WaComms.js +4 -0
- package/dist/esm/transport/keepalive/WaKeepAlive.js +4 -0
- package/dist/message/primitives/incoming.js +6 -2
- package/dist/transport/WaComms.js +4 -0
- package/dist/transport/keepalive/WaKeepAlive.js +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/vinikjkkj/zapo/master/.github/assets/logo.png" />
|
|
4
|
+
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/vinikjkkj/zapo/master/.github/assets/logo-light.png" />
|
|
5
|
+
<img src="https://raw.githubusercontent.com/vinikjkkj/zapo/master/.github/assets/logo-light.png" alt="zapo" width="400" />
|
|
6
|
+
</picture>
|
|
3
7
|
</p>
|
|
4
8
|
|
|
5
9
|
<p align="center">
|
|
@@ -11,6 +11,7 @@ const WaAdvSignature_1 = require("../../signal/attestation/WaAdvSignature");
|
|
|
11
11
|
const global_1 = require("../../transport/node/builders/global");
|
|
12
12
|
const pairing_1 = require("../../transport/node/builders/pairing");
|
|
13
13
|
const helpers_1 = require("../../transport/node/helpers");
|
|
14
|
+
const query_1 = require("../../transport/node/query");
|
|
14
15
|
const bytes_1 = require("../../util/bytes");
|
|
15
16
|
class WaPairingFlow {
|
|
16
17
|
constructor(options) {
|
|
@@ -49,6 +50,7 @@ class WaPairingFlow {
|
|
|
49
50
|
responseTag: response.tag,
|
|
50
51
|
responseType: response.attrs.type
|
|
51
52
|
});
|
|
53
|
+
(0, query_1.assertIqResult)(response, 'companion hello');
|
|
52
54
|
const linkCodeNode = (0, helpers_1.findNodeChild)(response, constants_1.WA_NODE_TAGS.LINK_CODE_COMPANION_REG);
|
|
53
55
|
if (!linkCodeNode) {
|
|
54
56
|
throw new Error('companion hello response missing link_code_companion_reg');
|
package/dist/client/WaClient.js
CHANGED
|
@@ -258,10 +258,28 @@ class WaClient extends node_events_1.EventEmitter {
|
|
|
258
258
|
return;
|
|
259
259
|
}
|
|
260
260
|
if (protocolType === _proto_1.proto.Message.ProtocolMessage.Type.HISTORY_SYNC_NOTIFICATION) {
|
|
261
|
-
if (
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
261
|
+
if (!protocolMessage.historySyncNotification) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
const peerRemoteJid = event.key.remoteJid;
|
|
265
|
+
const peerStanzaId = event.key.id;
|
|
266
|
+
const sendHistSyncReceipt = peerRemoteJid && peerStanzaId
|
|
267
|
+
? async () => {
|
|
268
|
+
try {
|
|
269
|
+
await this.message.sendReceipt(peerRemoteJid, peerStanzaId, {
|
|
270
|
+
type: constants_1.WA_MESSAGE_TYPES.RECEIPT_TYPE_HISTORY_SYNC
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
catch (err) {
|
|
274
|
+
this.logger.warn('failed to send hist_sync receipt', {
|
|
275
|
+
id: peerStanzaId,
|
|
276
|
+
to: peerRemoteJid,
|
|
277
|
+
message: (0, primitives_1.toError)(err).message
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
: undefined;
|
|
282
|
+
if (this.options.history?.enabled !== false) {
|
|
265
283
|
await (0, history_sync_1.runHistorySyncNotification)({
|
|
266
284
|
logger: this.logger,
|
|
267
285
|
mediaTransfer: this.mediaTransfer,
|
|
@@ -269,24 +287,12 @@ class WaClient extends node_events_1.EventEmitter {
|
|
|
269
287
|
emitEvent: this.emit.bind(this),
|
|
270
288
|
onPrivacyTokens: (conversations) => this.deps.trustedContactToken.hydrateFromHistorySync(conversations),
|
|
271
289
|
onNctSalt: (salt) => this.deps.trustedContactToken.hydrateNctSaltFromHistorySync(salt),
|
|
272
|
-
onProcessed:
|
|
273
|
-
? async () => {
|
|
274
|
-
try {
|
|
275
|
-
await this.message.sendReceipt(peerRemoteJid, peerStanzaId, {
|
|
276
|
-
type: constants_1.WA_MESSAGE_TYPES.RECEIPT_TYPE_HISTORY_SYNC
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
catch (err) {
|
|
280
|
-
this.logger.warn('failed to send hist_sync receipt', {
|
|
281
|
-
id: peerStanzaId,
|
|
282
|
-
to: peerRemoteJid,
|
|
283
|
-
message: (0, primitives_1.toError)(err).message
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
: undefined
|
|
290
|
+
onProcessed: sendHistSyncReceipt
|
|
288
291
|
}, protocolMessage.historySyncNotification);
|
|
289
292
|
}
|
|
293
|
+
else if (sendHistSyncReceipt) {
|
|
294
|
+
await sendHistSyncReceipt();
|
|
295
|
+
}
|
|
290
296
|
return;
|
|
291
297
|
}
|
|
292
298
|
if (SYNC_RELATED_PROTOCOL_TYPES.has(protocolType)) {
|
|
@@ -391,7 +391,7 @@ class WaIncomingNodeCoordinator {
|
|
|
391
391
|
try {
|
|
392
392
|
const routingInfo = (0, helpers_1.decodeNodeContentBase64OrBytes)(routingInfoNode.content, `ib.${constants_1.WA_NODE_TAGS.EDGE_ROUTING}.${constants_1.WA_NODE_TAGS.ROUTING_INFO}`);
|
|
393
393
|
await this.runtime.persistRoutingInfo(routingInfo);
|
|
394
|
-
this.logger.
|
|
394
|
+
this.logger.debug('updated routing info from info bulletin', {
|
|
395
395
|
byteLength: routingInfo.byteLength
|
|
396
396
|
});
|
|
397
397
|
}
|
|
@@ -50,7 +50,6 @@ export declare class WaRetryCoordinator {
|
|
|
50
50
|
private isRetryReceiptNode;
|
|
51
51
|
private prepareDecryptFailureRetry;
|
|
52
52
|
private sendDecryptFailureRetryReceipt;
|
|
53
|
-
private resolvePeerRetryRecipient;
|
|
54
53
|
private handleParsedRetryRequest;
|
|
55
54
|
private processRetryRequest;
|
|
56
55
|
private prepareRetryResend;
|
|
@@ -169,7 +169,7 @@ class WaRetryCoordinator {
|
|
|
169
169
|
};
|
|
170
170
|
}
|
|
171
171
|
async sendDecryptFailureRetryReceipt(context, prepared) {
|
|
172
|
-
const recipient = context
|
|
172
|
+
const { recipient } = context;
|
|
173
173
|
const retryReceiptNode = (0, retry_1.buildRetryReceiptNode)({
|
|
174
174
|
stanzaId: context.stanzaId,
|
|
175
175
|
to: context.from,
|
|
@@ -194,26 +194,6 @@ class WaRetryCoordinator {
|
|
|
194
194
|
withKeys: prepared.retryKeys !== undefined
|
|
195
195
|
});
|
|
196
196
|
}
|
|
197
|
-
resolvePeerRetryRecipient(context) {
|
|
198
|
-
if (!context.participant) {
|
|
199
|
-
return undefined;
|
|
200
|
-
}
|
|
201
|
-
const meLid = this.deps.getCurrentCredentials()?.meLid;
|
|
202
|
-
if (!meLid) {
|
|
203
|
-
return undefined;
|
|
204
|
-
}
|
|
205
|
-
try {
|
|
206
|
-
const participantUser = (0, jid_1.toUserJid)(context.participant);
|
|
207
|
-
const meUserLid = (0, jid_1.toUserJid)(meLid);
|
|
208
|
-
if (participantUser !== meUserLid) {
|
|
209
|
-
return undefined;
|
|
210
|
-
}
|
|
211
|
-
return meUserLid;
|
|
212
|
-
}
|
|
213
|
-
catch {
|
|
214
|
-
return undefined;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
197
|
async handleParsedRetryRequest(receiptNode, request) {
|
|
218
198
|
if (request.type === constants_1.WA_MESSAGE_TYPES.RECEIPT_TYPE_ENC_REKEY_RETRY) {
|
|
219
199
|
this.deps.logger.debug('received enc_rekey_retry request (voip path deferred)', {
|
|
@@ -88,12 +88,14 @@ function extractIgnoreKeyContext(node, meJid) {
|
|
|
88
88
|
const me = tryParseJid(meJid);
|
|
89
89
|
const fromCandidates = collectFromCandidates(kind, a);
|
|
90
90
|
const fromMe = me !== null && fromCandidates.some((f) => tryParseJid(f)?.address.user === me.address.user);
|
|
91
|
+
// Device-stripped to match the JID form used by events/keys; a userless
|
|
92
|
+
// server `from` like `s.whatsapp.net` is unparseable, so fall back to raw.
|
|
91
93
|
return {
|
|
92
94
|
kind,
|
|
93
|
-
remoteJid: a.from ?? null,
|
|
95
|
+
remoteJid: tryParseJid(a.from)?.userJid ?? a.from ?? null,
|
|
94
96
|
fromMe,
|
|
95
97
|
id: a.id,
|
|
96
|
-
participant: a.participant ?? null
|
|
98
|
+
participant: tryParseJid(a.participant)?.userJid ?? a.participant ?? null
|
|
97
99
|
};
|
|
98
100
|
}
|
|
99
101
|
/** Pure matcher. Exported for direct testing without a coordinator. */
|
package/dist/client/types.d.ts
CHANGED
|
@@ -423,27 +423,30 @@ export interface WaIgnoreKey {
|
|
|
423
423
|
* Lib derives `kind` from the stanza tag and resolves `fromMe` by comparing
|
|
424
424
|
* every from-candidate (`from`, `sender_pn`, `sender_lid`) against `meJid`.
|
|
425
425
|
*
|
|
426
|
-
* `remoteJid` and `participant`
|
|
427
|
-
*
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
*
|
|
426
|
+
* `remoteJid` and `participant` are the `from` / `participant` attrs with the
|
|
427
|
+
* `:device` segment stripped (bare `user@server`), matching the JID form used
|
|
428
|
+
* by message events and keys. A value that does not parse as a JID (e.g. a
|
|
429
|
+
* userless server `from` like `s.whatsapp.net`) is passed through unchanged.
|
|
430
|
+
* They do NOT include the descriptor-style
|
|
431
|
+
* alt-attr lookups (`sender_pn` / `sender_lid` / `participant_pn` /
|
|
432
|
+
* `participant_lid`) or PN↔LID normalization, so they stay in whichever
|
|
433
|
+
* addressing mode the stanza arrived in. To match by user identity regardless
|
|
434
|
+
* of addressing mode, use the descriptor form, which handles it.
|
|
432
435
|
*/
|
|
433
436
|
export interface WaIgnoreKeyContext {
|
|
434
437
|
readonly kind: WaIgnoreStanzaKind;
|
|
435
|
-
/**
|
|
438
|
+
/** `from` attr without `:device` (group JID for groups, PN or LID user JID for 1:1). */
|
|
436
439
|
readonly remoteJid: string | null;
|
|
437
440
|
readonly fromMe: boolean;
|
|
438
441
|
readonly id: string | undefined;
|
|
439
|
-
/**
|
|
442
|
+
/** `participant` attr without `:device`; `null` for non-group stanzas. */
|
|
440
443
|
readonly participant: string | null;
|
|
441
444
|
}
|
|
442
445
|
/**
|
|
443
446
|
* Predicate form of {@link WaClient.ignoreKey}. Return `true` to drop the
|
|
444
447
|
* stanza, `false` to let it through. Receives a {@link WaIgnoreKeyContext}
|
|
445
|
-
* with the
|
|
446
|
-
*
|
|
448
|
+
* with the device-stripped `from`/`participant` (see the context's JSDoc for
|
|
449
|
+
* the addressing-mode caveat) plus lib-resolved `kind` and `fromMe`.
|
|
447
450
|
*/
|
|
448
451
|
export type WaIgnoreKeyPredicate = (ctx: WaIgnoreKeyContext) => boolean;
|
|
449
452
|
export interface WaIncomingBaseEvent {
|
|
@@ -8,6 +8,7 @@ import { ADV_PREFIX_HOSTED_ACCOUNT_SIGNATURE, computeAdvIdentityHmac, generateDe
|
|
|
8
8
|
import { buildAckNode, buildIqResultNode } from '../../transport/node/builders/global.js';
|
|
9
9
|
import { buildCompanionFinishRequestNode, buildCompanionHelloRequestNode, buildGetCountryCodeRequestNode } from '../../transport/node/builders/pairing.js';
|
|
10
10
|
import { decodeNodeContentUtf8OrBytes, findNodeChild, findNodeChildrenByTags, getFirstNodeChild, getNodeChildrenNonEmptyUtf8ByTag, hasNodeChild } from '../../transport/node/helpers.js';
|
|
11
|
+
import { assertIqResult } from '../../transport/node/query.js';
|
|
11
12
|
import { concatBytes, decodeProtoBytes, uint8Equal, uint8TimingSafeEqual } from '../../util/bytes.js';
|
|
12
13
|
export class WaPairingFlow {
|
|
13
14
|
constructor(options) {
|
|
@@ -46,6 +47,7 @@ export class WaPairingFlow {
|
|
|
46
47
|
responseTag: response.tag,
|
|
47
48
|
responseType: response.attrs.type
|
|
48
49
|
});
|
|
50
|
+
assertIqResult(response, 'companion hello');
|
|
49
51
|
const linkCodeNode = findNodeChild(response, WA_NODE_TAGS.LINK_CODE_COMPANION_REG);
|
|
50
52
|
if (!linkCodeNode) {
|
|
51
53
|
throw new Error('companion hello response missing link_code_companion_reg');
|
|
@@ -255,10 +255,28 @@ export class WaClient extends EventEmitter {
|
|
|
255
255
|
return;
|
|
256
256
|
}
|
|
257
257
|
if (protocolType === proto.Message.ProtocolMessage.Type.HISTORY_SYNC_NOTIFICATION) {
|
|
258
|
-
if (
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
258
|
+
if (!protocolMessage.historySyncNotification) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
const peerRemoteJid = event.key.remoteJid;
|
|
262
|
+
const peerStanzaId = event.key.id;
|
|
263
|
+
const sendHistSyncReceipt = peerRemoteJid && peerStanzaId
|
|
264
|
+
? async () => {
|
|
265
|
+
try {
|
|
266
|
+
await this.message.sendReceipt(peerRemoteJid, peerStanzaId, {
|
|
267
|
+
type: WA_MESSAGE_TYPES.RECEIPT_TYPE_HISTORY_SYNC
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
this.logger.warn('failed to send hist_sync receipt', {
|
|
272
|
+
id: peerStanzaId,
|
|
273
|
+
to: peerRemoteJid,
|
|
274
|
+
message: toError(err).message
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
: undefined;
|
|
279
|
+
if (this.options.history?.enabled !== false) {
|
|
262
280
|
await runHistorySyncNotification({
|
|
263
281
|
logger: this.logger,
|
|
264
282
|
mediaTransfer: this.mediaTransfer,
|
|
@@ -266,24 +284,12 @@ export class WaClient extends EventEmitter {
|
|
|
266
284
|
emitEvent: this.emit.bind(this),
|
|
267
285
|
onPrivacyTokens: (conversations) => this.deps.trustedContactToken.hydrateFromHistorySync(conversations),
|
|
268
286
|
onNctSalt: (salt) => this.deps.trustedContactToken.hydrateNctSaltFromHistorySync(salt),
|
|
269
|
-
onProcessed:
|
|
270
|
-
? async () => {
|
|
271
|
-
try {
|
|
272
|
-
await this.message.sendReceipt(peerRemoteJid, peerStanzaId, {
|
|
273
|
-
type: WA_MESSAGE_TYPES.RECEIPT_TYPE_HISTORY_SYNC
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
catch (err) {
|
|
277
|
-
this.logger.warn('failed to send hist_sync receipt', {
|
|
278
|
-
id: peerStanzaId,
|
|
279
|
-
to: peerRemoteJid,
|
|
280
|
-
message: toError(err).message
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
: undefined
|
|
287
|
+
onProcessed: sendHistSyncReceipt
|
|
285
288
|
}, protocolMessage.historySyncNotification);
|
|
286
289
|
}
|
|
290
|
+
else if (sendHistSyncReceipt) {
|
|
291
|
+
await sendHistSyncReceipt();
|
|
292
|
+
}
|
|
287
293
|
return;
|
|
288
294
|
}
|
|
289
295
|
if (SYNC_RELATED_PROTOCOL_TYPES.has(protocolType)) {
|
|
@@ -388,7 +388,7 @@ export class WaIncomingNodeCoordinator {
|
|
|
388
388
|
try {
|
|
389
389
|
const routingInfo = decodeNodeContentBase64OrBytes(routingInfoNode.content, `ib.${WA_NODE_TAGS.EDGE_ROUTING}.${WA_NODE_TAGS.ROUTING_INFO}`);
|
|
390
390
|
await this.runtime.persistRoutingInfo(routingInfo);
|
|
391
|
-
this.logger.
|
|
391
|
+
this.logger.debug('updated routing info from info bulletin', {
|
|
392
392
|
byteLength: routingInfo.byteLength
|
|
393
393
|
});
|
|
394
394
|
}
|
|
@@ -166,7 +166,7 @@ export class WaRetryCoordinator {
|
|
|
166
166
|
};
|
|
167
167
|
}
|
|
168
168
|
async sendDecryptFailureRetryReceipt(context, prepared) {
|
|
169
|
-
const recipient = context
|
|
169
|
+
const { recipient } = context;
|
|
170
170
|
const retryReceiptNode = buildRetryReceiptNode({
|
|
171
171
|
stanzaId: context.stanzaId,
|
|
172
172
|
to: context.from,
|
|
@@ -191,26 +191,6 @@ export class WaRetryCoordinator {
|
|
|
191
191
|
withKeys: prepared.retryKeys !== undefined
|
|
192
192
|
});
|
|
193
193
|
}
|
|
194
|
-
resolvePeerRetryRecipient(context) {
|
|
195
|
-
if (!context.participant) {
|
|
196
|
-
return undefined;
|
|
197
|
-
}
|
|
198
|
-
const meLid = this.deps.getCurrentCredentials()?.meLid;
|
|
199
|
-
if (!meLid) {
|
|
200
|
-
return undefined;
|
|
201
|
-
}
|
|
202
|
-
try {
|
|
203
|
-
const participantUser = toUserJid(context.participant);
|
|
204
|
-
const meUserLid = toUserJid(meLid);
|
|
205
|
-
if (participantUser !== meUserLid) {
|
|
206
|
-
return undefined;
|
|
207
|
-
}
|
|
208
|
-
return meUserLid;
|
|
209
|
-
}
|
|
210
|
-
catch {
|
|
211
|
-
return undefined;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
194
|
async handleParsedRetryRequest(receiptNode, request) {
|
|
215
195
|
if (request.type === WA_MESSAGE_TYPES.RECEIPT_TYPE_ENC_REKEY_RETRY) {
|
|
216
196
|
this.deps.logger.debug('received enc_rekey_retry request (voip path deferred)', {
|
|
@@ -82,12 +82,14 @@ export function extractIgnoreKeyContext(node, meJid) {
|
|
|
82
82
|
const me = tryParseJid(meJid);
|
|
83
83
|
const fromCandidates = collectFromCandidates(kind, a);
|
|
84
84
|
const fromMe = me !== null && fromCandidates.some((f) => tryParseJid(f)?.address.user === me.address.user);
|
|
85
|
+
// Device-stripped to match the JID form used by events/keys; a userless
|
|
86
|
+
// server `from` like `s.whatsapp.net` is unparseable, so fall back to raw.
|
|
85
87
|
return {
|
|
86
88
|
kind,
|
|
87
|
-
remoteJid: a.from ?? null,
|
|
89
|
+
remoteJid: tryParseJid(a.from)?.userJid ?? a.from ?? null,
|
|
88
90
|
fromMe,
|
|
89
91
|
id: a.id,
|
|
90
|
-
participant: a.participant ?? null
|
|
92
|
+
participant: tryParseJid(a.participant)?.userJid ?? a.participant ?? null
|
|
91
93
|
};
|
|
92
94
|
}
|
|
93
95
|
/** Pure matcher. Exported for direct testing without a coordinator. */
|
|
@@ -229,7 +229,7 @@ function processMsmsgEncNode(node, encNode, senderJid, options) {
|
|
|
229
229
|
encPayload: decoded.encPayload
|
|
230
230
|
}
|
|
231
231
|
};
|
|
232
|
-
const chatJid = node.attrs.from;
|
|
232
|
+
const chatJid = node.attrs.from ? toUserJid(node.attrs.from) : node.attrs.from;
|
|
233
233
|
const sender = senderJid ? parseJidFull(senderJid) : null;
|
|
234
234
|
const isGroup = chatJid ? isGroupJid(chatJid) : false;
|
|
235
235
|
const isBroadcast = chatJid ? isBroadcastJid(chatJid) : false;
|
|
@@ -302,7 +302,11 @@ async function decryptAndProcessEncNode(node, encNode, encType, senderJid, optio
|
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
304
|
if (shouldEmitIncomingMessage(message)) {
|
|
305
|
-
|
|
305
|
+
// remoteJid is the chat identity, which is deviceless: the device
|
|
306
|
+
// lives in senderDevice (from senderAddress), so strip any `:device`
|
|
307
|
+
// segment the `from` attr carries for 1:1 chats.
|
|
308
|
+
const fromAttr = node.attrs.from;
|
|
309
|
+
const chatJid = fromAttr ? toUserJid(fromAttr) : fromAttr;
|
|
306
310
|
const isGroup = chatJid ? isGroupJid(chatJid) : false;
|
|
307
311
|
const isBroadcast = chatJid ? isBroadcastJid(chatJid) : false;
|
|
308
312
|
const senderUserJid = `${senderAddress.user}@${senderAddress.server}`;
|
|
@@ -169,6 +169,10 @@ export class WaComms {
|
|
|
169
169
|
await this.socket.close(1000, 'stop_comms');
|
|
170
170
|
}
|
|
171
171
|
async closeSocketAndResume() {
|
|
172
|
+
if (!this.started || this.preventRetry) {
|
|
173
|
+
this.logger.debug('comms resume skipped: comms stopped or retry disabled');
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
172
176
|
this.logger.debug('comms close socket and resume requested');
|
|
173
177
|
this.resetConnectionState({
|
|
174
178
|
started: true,
|
|
@@ -101,6 +101,10 @@ export class WaKeepAlive {
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
catch (error) {
|
|
104
|
+
if (generation !== this.generation) {
|
|
105
|
+
this.logger.trace('keepalive stopped during in-flight ping, not resuming');
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
104
108
|
this.logger.warn('keepalive ping failed, reconnecting socket', {
|
|
105
109
|
message: toError(error).message
|
|
106
110
|
});
|
|
@@ -233,7 +233,7 @@ function processMsmsgEncNode(node, encNode, senderJid, options) {
|
|
|
233
233
|
encPayload: decoded.encPayload
|
|
234
234
|
}
|
|
235
235
|
};
|
|
236
|
-
const chatJid = node.attrs.from;
|
|
236
|
+
const chatJid = node.attrs.from ? (0, jid_1.toUserJid)(node.attrs.from) : node.attrs.from;
|
|
237
237
|
const sender = senderJid ? (0, jid_1.parseJidFull)(senderJid) : null;
|
|
238
238
|
const isGroup = chatJid ? (0, jid_1.isGroupJid)(chatJid) : false;
|
|
239
239
|
const isBroadcast = chatJid ? (0, jid_1.isBroadcastJid)(chatJid) : false;
|
|
@@ -306,7 +306,11 @@ async function decryptAndProcessEncNode(node, encNode, encType, senderJid, optio
|
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
308
|
if (shouldEmitIncomingMessage(message)) {
|
|
309
|
-
|
|
309
|
+
// remoteJid is the chat identity, which is deviceless: the device
|
|
310
|
+
// lives in senderDevice (from senderAddress), so strip any `:device`
|
|
311
|
+
// segment the `from` attr carries for 1:1 chats.
|
|
312
|
+
const fromAttr = node.attrs.from;
|
|
313
|
+
const chatJid = fromAttr ? (0, jid_1.toUserJid)(fromAttr) : fromAttr;
|
|
310
314
|
const isGroup = chatJid ? (0, jid_1.isGroupJid)(chatJid) : false;
|
|
311
315
|
const isBroadcast = chatJid ? (0, jid_1.isBroadcastJid)(chatJid) : false;
|
|
312
316
|
const senderUserJid = `${senderAddress.user}@${senderAddress.server}`;
|
|
@@ -172,6 +172,10 @@ class WaComms {
|
|
|
172
172
|
await this.socket.close(1000, 'stop_comms');
|
|
173
173
|
}
|
|
174
174
|
async closeSocketAndResume() {
|
|
175
|
+
if (!this.started || this.preventRetry) {
|
|
176
|
+
this.logger.debug('comms resume skipped: comms stopped or retry disabled');
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
175
179
|
this.logger.debug('comms close socket and resume requested');
|
|
176
180
|
this.resetConnectionState({
|
|
177
181
|
started: true,
|
|
@@ -104,6 +104,10 @@ class WaKeepAlive {
|
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
catch (error) {
|
|
107
|
+
if (generation !== this.generation) {
|
|
108
|
+
this.logger.trace('keepalive stopped during in-flight ping, not resuming');
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
107
111
|
this.logger.warn('keepalive ping failed, reconnecting socket', {
|
|
108
112
|
message: (0, primitives_1.toError)(error).message
|
|
109
113
|
});
|