mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 16:02:26 +00:00
171 lines
5.8 KiB
JavaScript
171 lines
5.8 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import { decryptDM } from "../js/dmDecryptor.js";
|
|
|
|
test("decryptDM handles kind 4 events with nip04 ciphertext", async () => {
|
|
const nostrTools = await import("nostr-tools");
|
|
const { generateSecretKey, getPublicKey, nip04 } = nostrTools;
|
|
|
|
const senderSecret = generateSecretKey();
|
|
const recipientSecret = generateSecretKey();
|
|
|
|
const senderPubkey = getPublicKey(senderSecret);
|
|
const recipientPubkey = getPublicKey(recipientSecret);
|
|
|
|
const message = "Hello from kind 4";
|
|
const ciphertext = await nip04.encrypt(senderSecret, recipientPubkey, message);
|
|
|
|
const event = {
|
|
id: "kind4-event",
|
|
kind: 4,
|
|
created_at: Math.floor(Date.now() / 1000),
|
|
pubkey: senderPubkey,
|
|
tags: [["p", recipientPubkey]],
|
|
content: ciphertext,
|
|
};
|
|
|
|
const context = {
|
|
actorPubkey: recipientPubkey,
|
|
decryptors: [
|
|
{
|
|
scheme: "nip04",
|
|
priority: 0,
|
|
decrypt: (remotePubkey, cipher) =>
|
|
nip04.decrypt(recipientSecret, remotePubkey, cipher),
|
|
},
|
|
],
|
|
};
|
|
|
|
const result = await decryptDM(event, context);
|
|
|
|
assert.equal(result.ok, true, "decryptDM should succeed for kind 4 event");
|
|
assert.equal(result.plaintext, message, "plaintext should match original message");
|
|
assert.equal(result.scheme, "nip04", "scheme should resolve to nip04");
|
|
assert.equal(result.sender.pubkey, senderPubkey, "sender pubkey should match event");
|
|
assert.equal(result.recipients.length, 1, "recipient metadata should be populated");
|
|
assert.equal(result.recipients[0].pubkey, recipientPubkey);
|
|
assert.equal(result.direction, "incoming", "direction should be incoming for recipient");
|
|
});
|
|
|
|
test("decryptDM prefers recipient pubkeys when actor is the sender", async () => {
|
|
const nostrTools = await import("nostr-tools");
|
|
const { generateSecretKey, getPublicKey, nip04 } = nostrTools;
|
|
|
|
const senderSecret = generateSecretKey();
|
|
const recipientSecret = generateSecretKey();
|
|
|
|
const senderPubkey = getPublicKey(senderSecret);
|
|
const recipientPubkey = getPublicKey(recipientSecret);
|
|
|
|
const message = "Hello from the author";
|
|
const ciphertext = await nip04.encrypt(senderSecret, recipientPubkey, message);
|
|
|
|
const event = {
|
|
id: "outgoing-kind4",
|
|
kind: 4,
|
|
created_at: Math.floor(Date.now() / 1000),
|
|
pubkey: senderPubkey,
|
|
tags: [["p", recipientPubkey]],
|
|
content: ciphertext,
|
|
};
|
|
|
|
const context = {
|
|
actorPubkey: senderPubkey,
|
|
decryptors: [
|
|
{
|
|
scheme: "nip04",
|
|
priority: 0,
|
|
decrypt: (remotePubkey, cipher) =>
|
|
nip04.decrypt(senderSecret, remotePubkey, cipher),
|
|
},
|
|
],
|
|
};
|
|
|
|
const result = await decryptDM(event, context);
|
|
|
|
assert.equal(result.ok, true, "decryptDM should succeed for outgoing event");
|
|
assert.equal(result.plaintext, message, "plaintext should match outgoing message");
|
|
assert.equal(result.recipients.length, 1, "recipient metadata should remain intact");
|
|
assert.equal(result.recipients[0].pubkey, recipientPubkey);
|
|
assert.equal(result.direction, "outgoing", "direction should be outgoing for the author");
|
|
});
|
|
|
|
test("decryptDM unwraps kind 1059 gift wraps with nip44", async () => {
|
|
const nostrTools = await import("nostr-tools");
|
|
const { generateSecretKey, getPublicKey, nip44, nip59 } = nostrTools;
|
|
|
|
const senderSecret = generateSecretKey();
|
|
const recipientSecret = generateSecretKey();
|
|
|
|
const senderPubkey = getPublicKey(senderSecret);
|
|
const recipientPubkey = getPublicKey(recipientSecret);
|
|
|
|
const baseEvent = {
|
|
kind: 14,
|
|
content: "Gift wrapped hello",
|
|
tags: [["p", recipientPubkey]],
|
|
created_at: Math.floor(Date.now() / 1000),
|
|
};
|
|
|
|
const wrap = nip59.wrapEvent(baseEvent, senderSecret, recipientPubkey);
|
|
|
|
const nip44Module = nip44.v2 ?? nip44;
|
|
const getConversationKey =
|
|
typeof nip44Module?.getConversationKey === "function"
|
|
? nip44Module.getConversationKey.bind(nip44Module)
|
|
: typeof nip44Module?.utils?.getConversationKey === "function"
|
|
? nip44Module.utils.getConversationKey.bind(nip44Module.utils)
|
|
: null;
|
|
const decryptFn =
|
|
typeof nip44Module?.decrypt === "function"
|
|
? nip44Module.decrypt.bind(nip44Module)
|
|
: typeof nip44?.v2?.decrypt === "function"
|
|
? nip44.v2.decrypt.bind(nip44.v2)
|
|
: null;
|
|
|
|
assert.ok(getConversationKey && decryptFn, "nip44 helpers should be available for tests");
|
|
|
|
const context = {
|
|
actorPubkey: recipientPubkey,
|
|
decryptors: [
|
|
{
|
|
scheme: "nip44_v2",
|
|
priority: 0,
|
|
supportsGiftWrap: true,
|
|
decrypt: (remotePubkey, cipher) => {
|
|
const conversationKey = getConversationKey(recipientSecret, remotePubkey);
|
|
return decryptFn(cipher, conversationKey);
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
const result = await decryptDM(wrap, context);
|
|
|
|
assert.equal(result.ok, true, "decryptDM should succeed for gift wrap event");
|
|
assert.equal(
|
|
result.plaintext,
|
|
baseEvent.content,
|
|
"plaintext should match unwrap payload",
|
|
);
|
|
assert.equal(result.sender.pubkey, senderPubkey, "sender should match rumor pubkey");
|
|
assert.equal(result.scheme, "nip44_v2", "scheme should report nip44 variant");
|
|
assert.equal(result.direction, "incoming", "direction should be incoming for recipient");
|
|
assert.ok(result.envelope && result.envelope.seal, "seal metadata should be provided");
|
|
assert.equal(
|
|
result.recipients[0].pubkey,
|
|
recipientPubkey,
|
|
"recipient metadata should reflect unwrap target",
|
|
);
|
|
});
|
|
|
|
test("decryptDM returns failure when decryptors are unavailable", async () => {
|
|
const event = { id: "unhandled", kind: 4, content: "", pubkey: "" };
|
|
|
|
const result = await decryptDM(event, { decryptors: [] });
|
|
|
|
assert.equal(result.ok, false, "decryptDM should report failure");
|
|
assert.ok(Array.isArray(result.errors), "failure payload should include errors");
|
|
});
|