@whanext/core 0.19.10 → 0.19.12
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/CHANGELOG.md +12 -0
- package/dist/index.js +135 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.19.12
|
|
4
|
+
|
|
5
|
+
- Added end-to-end AntiEdit diagnostics for encrypted addons, protocol events, direct edit envelopes, normalization, previous-message recovery, and final `messageEdited` emission.
|
|
6
|
+
- Missing parent secrets during Zapo edit-addon decryption now surface as a dedicated `decrypt_failed_missing_parent_secret` warning.
|
|
7
|
+
- Diagnostics contain message identifiers and processing stages, but never message text or encrypted payload bytes.
|
|
8
|
+
|
|
9
|
+
## 0.19.11
|
|
10
|
+
|
|
11
|
+
- Direct `editedMessage` envelopes are now translated into `messageEdited` events instead of being emitted as ordinary messages.
|
|
12
|
+
- View-once detection now follows multi-device and transparent message wrappers before classifying received media.
|
|
13
|
+
- Added regression coverage for direct edit envelopes and device-sent view-once media.
|
|
14
|
+
|
|
3
15
|
## 0.19.10
|
|
4
16
|
|
|
5
17
|
- Fixed restored sessions incorrectly waiting for a pairing challenge after the WhatsApp connection was already open.
|
package/dist/index.js
CHANGED
|
@@ -2434,7 +2434,8 @@ function isZapoViewOnceContent(input) {
|
|
|
2434
2434
|
if (input.viewOnceMessage?.message || input.viewOnceMessageV2?.message || viewOnceV2ExtensionMessage(input)) {
|
|
2435
2435
|
return true;
|
|
2436
2436
|
}
|
|
2437
|
-
|
|
2437
|
+
const nested = input.ephemeralMessage?.message ?? input.deviceSentMessage?.message ?? input.documentWithCaptionMessage?.message ?? editedWrapperMessage(input);
|
|
2438
|
+
return nested ? isZapoViewOnceContent(nested) : false;
|
|
2438
2439
|
}
|
|
2439
2440
|
function extractQuotedZapoMessage(input) {
|
|
2440
2441
|
const event = input;
|
|
@@ -3111,12 +3112,44 @@ var ZapoProvider = class {
|
|
|
3111
3112
|
client.on("message", (event) => {
|
|
3112
3113
|
const protocol = this.#protocolMessage(event);
|
|
3113
3114
|
if (protocol && this.#isMessageMutationProtocol(protocol.type)) {
|
|
3115
|
+
if (protocol.type === proto.Message.ProtocolMessage.Type.MESSAGE_EDIT) {
|
|
3116
|
+
this.#logEditDiagnostic("received_message_protocol_payload", {
|
|
3117
|
+
eventMessageId: event.key.id ?? void 0,
|
|
3118
|
+
targetMessageId: protocol.key?.id ?? void 0,
|
|
3119
|
+
offline: event.offline === true
|
|
3120
|
+
});
|
|
3121
|
+
}
|
|
3114
3122
|
this.#enqueueProtocolEvent({
|
|
3115
3123
|
...event,
|
|
3116
3124
|
protocolMessage: protocol
|
|
3117
3125
|
});
|
|
3118
3126
|
return;
|
|
3119
3127
|
}
|
|
3128
|
+
const directEdit = this.#directEditedMessage(event.message);
|
|
3129
|
+
if (directEdit && event.key.id) {
|
|
3130
|
+
this.#logEditDiagnostic("received_direct_edited_message", {
|
|
3131
|
+
eventMessageId: event.key.id,
|
|
3132
|
+
targetMessageId: event.key.id,
|
|
3133
|
+
offline: event.offline === true
|
|
3134
|
+
});
|
|
3135
|
+
this.#enqueueProtocolEvent({
|
|
3136
|
+
...event,
|
|
3137
|
+
protocolMessage: {
|
|
3138
|
+
type: proto.Message.ProtocolMessage.Type.MESSAGE_EDIT,
|
|
3139
|
+
key: event.key,
|
|
3140
|
+
editedMessage: directEdit
|
|
3141
|
+
}
|
|
3142
|
+
});
|
|
3143
|
+
return;
|
|
3144
|
+
}
|
|
3145
|
+
const encryptedEdit = this.#encryptedEditInfo(event.message);
|
|
3146
|
+
if (encryptedEdit) {
|
|
3147
|
+
this.#logEditDiagnostic("received_encrypted_addon", {
|
|
3148
|
+
eventMessageId: event.key.id ?? void 0,
|
|
3149
|
+
targetMessageId: encryptedEdit.targetMessageId,
|
|
3150
|
+
offline: event.offline === true
|
|
3151
|
+
});
|
|
3152
|
+
}
|
|
3120
3153
|
this.#handleMessage(event);
|
|
3121
3154
|
});
|
|
3122
3155
|
client.on("message_send", (event) => {
|
|
@@ -3132,6 +3165,13 @@ var ZapoProvider = class {
|
|
|
3132
3165
|
});
|
|
3133
3166
|
});
|
|
3134
3167
|
client.on("message_protocol", (event) => {
|
|
3168
|
+
if (event.protocolMessage.type === proto.Message.ProtocolMessage.Type.MESSAGE_EDIT) {
|
|
3169
|
+
this.#logEditDiagnostic("received_message_protocol_event", {
|
|
3170
|
+
eventMessageId: event.key.id ?? void 0,
|
|
3171
|
+
targetMessageId: event.protocolMessage.key?.id ?? void 0,
|
|
3172
|
+
offline: event.offline === true
|
|
3173
|
+
});
|
|
3174
|
+
}
|
|
3135
3175
|
this.#enqueueProtocolEvent(event);
|
|
3136
3176
|
});
|
|
3137
3177
|
client.on("message_addon", (event) => {
|
|
@@ -3189,10 +3229,29 @@ var ZapoProvider = class {
|
|
|
3189
3229
|
const kind = event.kind ?? this.#stringField(decrypted, "kind") ?? this.#stringField(decrypted, "type");
|
|
3190
3230
|
const isEdit = kind === "message_edit" || protocol?.type === proto.Message.ProtocolMessage.Type.MESSAGE_EDIT;
|
|
3191
3231
|
if (!isEdit) return;
|
|
3232
|
+
this.#logEditDiagnostic("received_decrypted_addon", {
|
|
3233
|
+
eventMessageId: event.key.id ?? void 0,
|
|
3234
|
+
targetMessageId: event.targetMessageId ?? this.#stringField(decrypted, "targetMessageId") ?? this.#stringField(decrypted, "targetMessageID") ?? protocol?.key?.id ?? void 0,
|
|
3235
|
+
addonKind: kind ?? void 0,
|
|
3236
|
+
offline: event.offline === true
|
|
3237
|
+
});
|
|
3192
3238
|
const targetMessageId = event.targetMessageId ?? this.#stringField(decrypted, "targetMessageId") ?? this.#stringField(decrypted, "targetMessageID") ?? protocol?.key?.id ?? void 0;
|
|
3193
|
-
if (!targetMessageId)
|
|
3239
|
+
if (!targetMessageId) {
|
|
3240
|
+
this.#logEditDiagnostic("dropped_addon_without_target", {
|
|
3241
|
+
eventMessageId: event.key.id ?? void 0,
|
|
3242
|
+
addonKind: kind ?? void 0
|
|
3243
|
+
}, "warn");
|
|
3244
|
+
return;
|
|
3245
|
+
}
|
|
3194
3246
|
const editedMessage = protocol?.editedMessage ?? this.#addonEditedMessage(event.decrypted);
|
|
3195
|
-
if (!editedMessage)
|
|
3247
|
+
if (!editedMessage) {
|
|
3248
|
+
this.#logEditDiagnostic("dropped_addon_without_edited_content", {
|
|
3249
|
+
eventMessageId: event.key.id ?? void 0,
|
|
3250
|
+
targetMessageId,
|
|
3251
|
+
addonKind: kind ?? void 0
|
|
3252
|
+
}, "warn");
|
|
3253
|
+
return;
|
|
3254
|
+
}
|
|
3196
3255
|
const protocolKey = protocol?.key;
|
|
3197
3256
|
const target = {
|
|
3198
3257
|
...protocolKey ?? {},
|
|
@@ -3268,6 +3327,31 @@ var ZapoProvider = class {
|
|
|
3268
3327
|
}
|
|
3269
3328
|
return value;
|
|
3270
3329
|
}
|
|
3330
|
+
#directEditedMessage(message) {
|
|
3331
|
+
if (!message) return void 0;
|
|
3332
|
+
const direct = message.editedMessage?.message;
|
|
3333
|
+
if (direct) return direct;
|
|
3334
|
+
const nested = message.ephemeralMessage?.message ?? message.deviceSentMessage?.message;
|
|
3335
|
+
return nested ? this.#directEditedMessage(nested) : void 0;
|
|
3336
|
+
}
|
|
3337
|
+
#encryptedEditInfo(message) {
|
|
3338
|
+
const content = unwrapZapoMessageContent(message);
|
|
3339
|
+
const encrypted = content?.secretEncryptedMessage;
|
|
3340
|
+
if (!encrypted) return void 0;
|
|
3341
|
+
if (encrypted.secretEncType !== proto.Message.SecretEncryptedMessage.SecretEncType.MESSAGE_EDIT) {
|
|
3342
|
+
return void 0;
|
|
3343
|
+
}
|
|
3344
|
+
return {
|
|
3345
|
+
...encrypted.targetMessageKey?.id ? { targetMessageId: encrypted.targetMessageKey.id } : {}
|
|
3346
|
+
};
|
|
3347
|
+
}
|
|
3348
|
+
#logEditDiagnostic(stage, context, level = "info") {
|
|
3349
|
+
this.#logger[level]("AntiEdit diagnostic", {
|
|
3350
|
+
diagnostic: "antiedit",
|
|
3351
|
+
stage,
|
|
3352
|
+
...context
|
|
3353
|
+
});
|
|
3354
|
+
}
|
|
3271
3355
|
#protocolMessage(event) {
|
|
3272
3356
|
if (event.protocolMessage) return event.protocolMessage;
|
|
3273
3357
|
const content = unwrapZapoMessageContent(event.message);
|
|
@@ -3305,10 +3389,15 @@ var ZapoProvider = class {
|
|
|
3305
3389
|
if (!protocol || !this.#isMessageMutationProtocol(protocol.type)) return;
|
|
3306
3390
|
const protocolKey = protocol.key;
|
|
3307
3391
|
if (!protocolKey?.id) {
|
|
3308
|
-
|
|
3392
|
+
const context = {
|
|
3309
3393
|
messageId: event.key.id ?? void 0,
|
|
3310
3394
|
protocolType: protocol.type ?? void 0
|
|
3311
|
-
}
|
|
3395
|
+
};
|
|
3396
|
+
if (protocol.type === proto.Message.ProtocolMessage.Type.MESSAGE_EDIT) {
|
|
3397
|
+
this.#logEditDiagnostic("dropped_protocol_without_target", context, "warn");
|
|
3398
|
+
} else {
|
|
3399
|
+
this.#logger.debug("Ignored Zapo protocol mutation without a target message id.", context);
|
|
3400
|
+
}
|
|
3312
3401
|
return;
|
|
3313
3402
|
}
|
|
3314
3403
|
const remoteJid = protocolKey.remoteJid ?? event.key.remoteJid;
|
|
@@ -3322,7 +3411,16 @@ var ZapoProvider = class {
|
|
|
3322
3411
|
};
|
|
3323
3412
|
const stored = await this.#findStoredMessage(target);
|
|
3324
3413
|
if (!target.remoteJid && stored?.key.remoteJid) target.remoteJid = stored.key.remoteJid;
|
|
3325
|
-
if (!target.remoteJid)
|
|
3414
|
+
if (!target.remoteJid) {
|
|
3415
|
+
if (protocol.type === proto.Message.ProtocolMessage.Type.MESSAGE_EDIT) {
|
|
3416
|
+
this.#logEditDiagnostic("dropped_edit_without_chat", {
|
|
3417
|
+
eventMessageId: event.key.id ?? void 0,
|
|
3418
|
+
targetMessageId: target.id ?? void 0,
|
|
3419
|
+
previousRecovered: stored !== void 0
|
|
3420
|
+
}, "warn");
|
|
3421
|
+
}
|
|
3422
|
+
return;
|
|
3423
|
+
}
|
|
3326
3424
|
const type = protocol.type;
|
|
3327
3425
|
const mutationKey = this.#protocolDeliveryKey(event, target, type);
|
|
3328
3426
|
if (mutationKey && this.#handledProtocolStore.has(mutationKey)) {
|
|
@@ -3353,7 +3451,13 @@ var ZapoProvider = class {
|
|
|
3353
3451
|
return;
|
|
3354
3452
|
}
|
|
3355
3453
|
const editedContent = protocol.editedMessage ? this.#unwrapEditedContent(protocol.editedMessage) : void 0;
|
|
3356
|
-
if (!editedContent)
|
|
3454
|
+
if (!editedContent) {
|
|
3455
|
+
this.#logEditDiagnostic("dropped_edit_without_content", {
|
|
3456
|
+
eventMessageId: event.key.id ?? void 0,
|
|
3457
|
+
targetMessageId: target.id ?? void 0
|
|
3458
|
+
}, "warn");
|
|
3459
|
+
return;
|
|
3460
|
+
}
|
|
3357
3461
|
const pushName = event.pushName ?? stored?.pushName;
|
|
3358
3462
|
const edited = {
|
|
3359
3463
|
...stored ?? {},
|
|
@@ -3366,18 +3470,31 @@ var ZapoProvider = class {
|
|
|
3366
3470
|
...pushName !== void 0 ? { pushName } : {}
|
|
3367
3471
|
};
|
|
3368
3472
|
const message = normalizeZapoMessage(edited);
|
|
3369
|
-
if (!message)
|
|
3473
|
+
if (!message) {
|
|
3474
|
+
this.#logEditDiagnostic("dropped_edit_normalization_failed", {
|
|
3475
|
+
eventMessageId: event.key.id ?? void 0,
|
|
3476
|
+
targetMessageId: target.id ?? void 0,
|
|
3477
|
+
previousRecovered: stored !== void 0
|
|
3478
|
+
}, "warn");
|
|
3479
|
+
return;
|
|
3480
|
+
}
|
|
3370
3481
|
const previous = stored ? normalizeZapoMessage(stored) : void 0;
|
|
3371
3482
|
if (mutationKey) this.#rememberHandledProtocol(mutationKey);
|
|
3372
3483
|
this.#remember(edited);
|
|
3373
3484
|
const editedByMe = event.key.fromMe === true;
|
|
3374
3485
|
const editedById = event.key.participant ?? event.key.participantAlt ?? (editedByMe ? this.getCurrentUserIds()[0] : event.key.remoteJid ?? void 0);
|
|
3375
3486
|
if (!previous) {
|
|
3376
|
-
this.#
|
|
3487
|
+
this.#logEditDiagnostic("emitting_without_previous_message", {
|
|
3377
3488
|
targetMessageId: target.id ?? void 0,
|
|
3378
3489
|
chatId: target.remoteJid ?? void 0
|
|
3379
|
-
});
|
|
3490
|
+
}, "warn");
|
|
3380
3491
|
}
|
|
3492
|
+
this.#logEditDiagnostic("emitting_message_edited", {
|
|
3493
|
+
eventMessageId: event.key.id ?? void 0,
|
|
3494
|
+
targetMessageId: target.id ?? void 0,
|
|
3495
|
+
previousRecovered: previous !== void 0,
|
|
3496
|
+
editedByMe
|
|
3497
|
+
});
|
|
3381
3498
|
void this.#events.emit("messageEdited", {
|
|
3382
3499
|
key: message.keys,
|
|
3383
3500
|
...previous ? { previous } : {},
|
|
@@ -4459,6 +4576,14 @@ var WhaNextZapoLogger = class _WhaNextZapoLogger {
|
|
|
4459
4576
|
this.#logger.info(message, this.#merge(context));
|
|
4460
4577
|
}
|
|
4461
4578
|
warn(message, context) {
|
|
4579
|
+
if (message.startsWith("addon parent message secret not found") && context?.kind === "message_edit") {
|
|
4580
|
+
this.#logger.warn("AntiEdit diagnostic", {
|
|
4581
|
+
diagnostic: "antiedit",
|
|
4582
|
+
stage: "decrypt_failed_missing_parent_secret",
|
|
4583
|
+
...this.#merge(context)
|
|
4584
|
+
});
|
|
4585
|
+
return;
|
|
4586
|
+
}
|
|
4462
4587
|
this.#logger.warn(message, this.#merge(context));
|
|
4463
4588
|
}
|
|
4464
4589
|
error(message, context) {
|