mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
The legacy-DM perf reorder regressed tests/nostr/dmDecryptorPreference: 1. preferLegacy short-circuited BEFORE the explicit-hint ranking, so a kind-4 event tagged ["encrypted","nip44"] would still try nip04 first. Explicit hints now win; preferLegacy only flips the *no-hint* default. 2. The "skip the actor's own key" optimization dropped self even when it was the ONLY candidate (note-to-self DMs), leaving zero candidates -> ok:false. Self is now deferred to last and attempted as a fallback instead of dropped. Spec correction (per Dark Factory rules): for a kind-4 DM with no hints, nip04 is now the preferred default (protocol-correct + avoids a wasted serialized nip-07 round-trip). Rewrote the preference test to assert: nip04-first default, explicit nip44 hint wins, nip04->nip44 fallback, and note-to-self decrypts. Co-Authored-By: Claude Opus 4.8 <[email protected]>
128 lines
3.5 KiB
JavaScript
128 lines
3.5 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import { decryptDM } from "../../js/dmDecryptor.js";
|
|
|
|
const buildHex = (value) => value.repeat(64);
|
|
|
|
const baseEvent = (pubkey, tags = []) => ({
|
|
kind: 4,
|
|
pubkey,
|
|
content: "ciphertext",
|
|
tags,
|
|
});
|
|
|
|
// SPEC: a legacy kind-4 DM is NIP-04 by convention. With no explicit encryption
|
|
// hint, try nip04 FIRST so we don't burn a slow, serialized nip-07 extension
|
|
// round-trip on nip44 before falling back. (Spec correction: the previous
|
|
// expectation preferred nip44 by default for kind-4, which caused every legacy
|
|
// DM to pay an extra extension call.)
|
|
test("decryptDM prefers nip04 first for legacy kind-4 DMs without hints", async () => {
|
|
const senderPubkey = buildHex("e");
|
|
|
|
const result = await decryptDM(baseEvent(senderPubkey), {
|
|
actorPubkey: senderPubkey,
|
|
decryptors: [
|
|
{
|
|
scheme: "nip04",
|
|
decrypt: async () => "nip04",
|
|
priority: 0,
|
|
},
|
|
{
|
|
scheme: "nip44",
|
|
decrypt: async () => "nip44",
|
|
priority: 0,
|
|
},
|
|
],
|
|
});
|
|
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.scheme, "nip04");
|
|
assert.equal(result.plaintext, "nip04");
|
|
});
|
|
|
|
// SPEC: an explicit per-event encryption hint always wins, even for kind-4. If
|
|
// the sender tagged the message nip44, decrypt with nip44 first regardless of
|
|
// the legacy default.
|
|
test("decryptDM honors an explicit nip44 hint on a kind-4 DM", async () => {
|
|
const senderPubkey = buildHex("a");
|
|
|
|
const result = await decryptDM(
|
|
baseEvent(senderPubkey, [["encrypted", "nip44"]]),
|
|
{
|
|
actorPubkey: senderPubkey,
|
|
decryptors: [
|
|
{
|
|
scheme: "nip04",
|
|
decrypt: async () => "nip04",
|
|
priority: 0,
|
|
},
|
|
{
|
|
scheme: "nip44",
|
|
decrypt: async () => "nip44",
|
|
priority: 0,
|
|
},
|
|
],
|
|
},
|
|
);
|
|
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.scheme, "nip44");
|
|
assert.equal(result.plaintext, "nip44");
|
|
});
|
|
|
|
// SPEC: when the preferred scheme fails, fall through to the next decryptor and
|
|
// still succeed. Here nip04 (tried first by the legacy default) throws, so the
|
|
// result must come from nip44.
|
|
test("decryptDM falls back to nip44 when the nip04 attempt fails", async () => {
|
|
const senderPubkey = buildHex("f");
|
|
|
|
const result = await decryptDM(baseEvent(senderPubkey), {
|
|
actorPubkey: senderPubkey,
|
|
decryptors: [
|
|
{
|
|
scheme: "nip04",
|
|
decrypt: async () => {
|
|
throw new Error("nip04 failure");
|
|
},
|
|
priority: 0,
|
|
},
|
|
{
|
|
scheme: "nip44",
|
|
decrypt: async () => "fallback",
|
|
priority: 0,
|
|
},
|
|
],
|
|
});
|
|
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.scheme, "nip44");
|
|
assert.equal(result.plaintext, "fallback");
|
|
});
|
|
|
|
// SPEC: a note-to-self DM has no counterparty other than the actor. The self
|
|
// key must still be attempted (deferred to last) rather than dropped, or the
|
|
// message can never decrypt.
|
|
test("decryptDM still decrypts a note-to-self DM (self is the only candidate)", async () => {
|
|
const selfPubkey = buildHex("b");
|
|
let attemptedRemote = null;
|
|
|
|
const result = await decryptDM(baseEvent(selfPubkey), {
|
|
actorPubkey: selfPubkey,
|
|
decryptors: [
|
|
{
|
|
scheme: "nip04",
|
|
decrypt: async (remotePubkey) => {
|
|
attemptedRemote = remotePubkey;
|
|
return "self-note";
|
|
},
|
|
priority: 0,
|
|
},
|
|
],
|
|
});
|
|
|
|
assert.equal(result.ok, true);
|
|
assert.equal(result.plaintext, "self-note");
|
|
assert.equal(attemptedRemote, selfPubkey);
|
|
});
|